Merge branch 'fix_metadata_refs' into split-me-baby-one-more-time
diff --git a/.gitignore b/.gitignore
index 502483f..ca61bda 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,7 +14,7 @@
 *.egg
 
 # Node installation output
-node_modules/
+^node_modules
 src/node/extension_binary/
 
 # gcov coverage data
diff --git a/BUILD b/BUILD
index f8e7661..b69c940 100644
--- a/BUILD
+++ b/BUILD
@@ -1136,6 +1136,8 @@
     "src/compiler/csharp_generator.h",
     "src/compiler/csharp_generator_helpers.h",
     "src/compiler/generator_helpers.h",
+    "src/compiler/node_generator.h",
+    "src/compiler/node_generator_helpers.h",
     "src/compiler/objective_c_generator.h",
     "src/compiler/objective_c_generator_helpers.h",
     "src/compiler/python_generator.h",
@@ -1145,6 +1147,7 @@
     "src/compiler/ruby_generator_string-inl.h",
     "src/compiler/cpp_generator.cc",
     "src/compiler/csharp_generator.cc",
+    "src/compiler/node_generator.cc",
     "src/compiler/objective_c_generator.cc",
     "src/compiler/python_generator.cc",
     "src/compiler/ruby_generator.cc",
@@ -1667,6 +1670,18 @@
 
 
 cc_binary(
+  name = "grpc_node_plugin",
+  srcs = [
+    "src/compiler/node_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+cc_binary(
   name = "grpc_objective_c_plugin",
   srcs = [
     "src/compiler/objective_c_plugin.cc",
diff --git a/Makefile b/Makefile
index 386c4a7..3b7dbd9 100644
--- a/Makefile
+++ b/Makefile
@@ -779,7 +779,7 @@
 
 .SECONDARY = %.pb.h %.pb.cc
 
-PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
+PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
 ifeq ($(DEP_MISSING),)
 all: static shared plugins
 dep_error:
@@ -1013,6 +1013,7 @@
 grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
 grpc_cpp_plugin: $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
 grpc_csharp_plugin: $(BINDIR)/$(CONFIG)/grpc_csharp_plugin
+grpc_node_plugin: $(BINDIR)/$(CONFIG)/grpc_node_plugin
 grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin
 grpc_python_plugin: $(BINDIR)/$(CONFIG)/grpc_python_plugin
 grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
@@ -2245,6 +2246,8 @@
 	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(prefix)/bin/grpc_csharp_plugin
 	$(Q) $(INSTALL) -d $(prefix)/bin
+	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_node_plugin $(prefix)/bin/grpc_node_plugin
+	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(prefix)/bin/grpc_objective_c_plugin
 	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_python_plugin $(prefix)/bin/grpc_python_plugin
@@ -3611,6 +3614,7 @@
 LIBGRPC_PLUGIN_SUPPORT_SRC = \
     src/compiler/cpp_generator.cc \
     src/compiler/csharp_generator.cc \
+    src/compiler/node_generator.cc \
     src/compiler/objective_c_generator.cc \
     src/compiler/python_generator.cc \
     src/compiler/ruby_generator.cc \
@@ -10545,6 +10549,37 @@
 endif
 
 
+GRPC_NODE_PLUGIN_SRC = \
+    src/compiler/node_plugin.cc \
+
+GRPC_NODE_PLUGIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_NODE_PLUGIN_SRC))))
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/grpc_node_plugin: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_node_plugin: $(PROTOBUF_DEP) $(GRPC_NODE_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
+	$(E) "[HOSTLD]  Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_NODE_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_node_plugin
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/compiler/node_plugin.o:  $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
+
+deps_grpc_node_plugin: $(GRPC_NODE_PLUGIN_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_NODE_PLUGIN_OBJS:.o=.dep)
+endif
+
+
 GRPC_OBJECTIVE_C_PLUGIN_SRC = \
     src/compiler/objective_c_plugin.cc \
 
diff --git a/build.yaml b/build.yaml
index 7248753..6c00b42 100644
--- a/build.yaml
+++ b/build.yaml
@@ -938,6 +938,8 @@
   - src/compiler/csharp_generator.h
   - src/compiler/csharp_generator_helpers.h
   - src/compiler/generator_helpers.h
+  - src/compiler/node_generator.h
+  - src/compiler/node_generator_helpers.h
   - src/compiler/objective_c_generator.h
   - src/compiler/objective_c_generator_helpers.h
   - src/compiler/python_generator.h
@@ -948,6 +950,7 @@
   src:
   - src/compiler/cpp_generator.cc
   - src/compiler/csharp_generator.cc
+  - src/compiler/node_generator.cc
   - src/compiler/objective_c_generator.cc
   - src/compiler/python_generator.cc
   - src/compiler/ruby_generator.cc
@@ -2582,6 +2585,15 @@
   secure: false
   vs_config_type: Application
   vs_project_guid: '{3C813052-A49A-4662-B90A-1ADBEC7EE453}'
+- name: grpc_node_plugin
+  build: protoc
+  language: c++
+  src:
+  - src/compiler/node_plugin.cc
+  deps:
+  - grpc_plugin_support
+  secure: false
+  vs_config_type: Application
 - name: grpc_objective_c_plugin
   build: protoc
   language: c++
diff --git a/examples/node/greeter_client.js b/examples/node/greeter_client.js
index 2820acb..7125c2f 100644
--- a/examples/node/greeter_client.js
+++ b/examples/node/greeter_client.js
@@ -31,22 +31,30 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
-
 var grpc = require('grpc');
-var hello_proto = grpc.load(PROTO_PATH).helloworld;
+
+var hello_messages = require('./helloworld_pb');
+var hello_service = require('./helloworld_grpc_pb');
 
 function main() {
-  var client = new hello_proto.Greeter('localhost:50051',
-                                       grpc.credentials.createInsecure());
+  var client = new hello_service.GreeterClient('localhost:50051',
+                                               grpc.credentials.createInsecure());
   var user;
   if (process.argv.length >= 3) {
     user = process.argv[2];
   } else {
     user = 'world';
   }
-  client.sayHello({name: user}, function(err, response) {
-    console.log('Greeting:', response.message);
+
+  var request = new hello_messages.HelloRequest();
+  request.setName(user);
+
+  client.sayHello(request, function(err, response) {
+    if (err) {
+      debugger;
+      throw err;
+    }
+    console.log('Greeting:', response.getMessage());
   });
 }
 
diff --git a/examples/node/greeter_server.js b/examples/node/greeter_server.js
index e7ad51f..a4aebf6 100644
--- a/examples/node/greeter_server.js
+++ b/examples/node/greeter_server.js
@@ -31,16 +31,18 @@
  *
  */
 
-var PROTO_PATH = __dirname + '/../protos/helloworld.proto';
-
 var grpc = require('grpc');
-var hello_proto = grpc.load(PROTO_PATH).helloworld;
+
+var hello_messages = require('./helloworld_pb');
+var hello_service = require('./helloworld_grpc_pb');
 
 /**
  * Implements the SayHello RPC method.
  */
 function sayHello(call, callback) {
-  callback(null, {message: 'Hello ' + call.request.name});
+  var reply = new hello_messages.HelloReply();
+  reply.setMessage("Hello " + call.request.getName());
+  callback(null, reply);
 }
 
 /**
@@ -49,7 +51,7 @@
  */
 function main() {
   var server = new grpc.Server();
-  server.addProtoService(hello_proto.Greeter.service, {sayHello: sayHello});
+  server.addService(hello_service.GreeterService, {sayHello: sayHello});
   server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
   server.start();
 }
diff --git a/examples/node/helloworld_grpc_pb.js b/examples/node/helloworld_grpc_pb.js
new file mode 100644
index 0000000..3d070d7
--- /dev/null
+++ b/examples/node/helloworld_grpc_pb.js
@@ -0,0 +1,39 @@
+// GENERATED CODE -- DO NOT EDIT!
+
+var grpc = require('grpc');
+var helloworld_pb = require('./helloworld_pb.js');
+
+function serialize_HelloReply(arg) {
+  if (!(arg instanceof helloworld_pb.HelloReply)) {
+    throw new Error('Expected argument of type HelloReply');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+function deserialize_HelloReply(buffer_arg) {
+  return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg));
+}
+function serialize_HelloRequest(arg) {
+  if (!(arg instanceof helloworld_pb.HelloRequest)) {
+    throw new Error('Expected argument of type HelloRequest');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+function deserialize_HelloRequest(buffer_arg) {
+  return helloworld_pb.HelloRequest.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+var GreeterService = exports.GreeterService = {
+  sayHello: {
+    path: '/helloworld.Greeter/SayHello',
+    requestStream: false,
+    responseStream: false,
+    requestType: helloworld_pb.HelloRequest,
+    responseType: helloworld_pb.HelloReply,
+    requestSerialize: serialize_HelloRequest,
+    requestDeserialize: deserialize_HelloRequest,
+    responseSerialize: serialize_HelloReply,
+    responseDeserialize: deserialize_HelloReply,
+  },
+};
+
+exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService);
diff --git a/examples/node/helloworld_pb.js b/examples/node/helloworld_pb.js
new file mode 100644
index 0000000..6405bd9
--- /dev/null
+++ b/examples/node/helloworld_pb.js
@@ -0,0 +1,332 @@
+/**
+ * @fileoverview
+ * @enhanceable
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.helloworld.HelloReply', null, global);
+goog.exportSymbol('proto.helloworld.HelloRequest', null, global);
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.helloworld.HelloRequest = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.helloworld.HelloRequest, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.helloworld.HelloRequest.displayName = 'proto.helloworld.HelloRequest';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.helloworld.HelloRequest.prototype.toObject = function(opt_includeInstance) {
+  return proto.helloworld.HelloRequest.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.helloworld.HelloRequest} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.helloworld.HelloRequest.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    name: msg.getName()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.helloworld.HelloRequest}
+ */
+proto.helloworld.HelloRequest.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.helloworld.HelloRequest;
+  return proto.helloworld.HelloRequest.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.helloworld.HelloRequest} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.helloworld.HelloRequest}
+ */
+proto.helloworld.HelloRequest.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setName(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.helloworld.HelloRequest} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloRequest.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.helloworld.HelloRequest.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloRequest.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getName();
+  if (f.length > 0) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.helloworld.HelloRequest} The clone.
+ */
+proto.helloworld.HelloRequest.prototype.cloneMessage = function() {
+  return /** @type {!proto.helloworld.HelloRequest} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional string name = 1;
+ * @return {string}
+ */
+proto.helloworld.HelloRequest.prototype.getName = function() {
+  return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
+};
+
+
+/** @param {string} value  */
+proto.helloworld.HelloRequest.prototype.setName = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.helloworld.HelloReply = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.helloworld.HelloReply, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.helloworld.HelloReply.displayName = 'proto.helloworld.HelloReply';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.helloworld.HelloReply.prototype.toObject = function(opt_includeInstance) {
+  return proto.helloworld.HelloReply.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.helloworld.HelloReply} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.helloworld.HelloReply.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    message: msg.getMessage()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.helloworld.HelloReply}
+ */
+proto.helloworld.HelloReply.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.helloworld.HelloReply;
+  return proto.helloworld.HelloReply.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.helloworld.HelloReply} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.helloworld.HelloReply}
+ */
+proto.helloworld.HelloReply.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setMessage(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.helloworld.HelloReply} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloReply.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.helloworld.HelloReply.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.helloworld.HelloReply.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getMessage();
+  if (f.length > 0) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.helloworld.HelloReply} The clone.
+ */
+proto.helloworld.HelloReply.prototype.cloneMessage = function() {
+  return /** @type {!proto.helloworld.HelloReply} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional string message = 1;
+ * @return {string}
+ */
+proto.helloworld.HelloReply.prototype.getMessage = function() {
+  return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
+};
+
+
+/** @param {string} value  */
+proto.helloworld.HelloReply.prototype.setMessage = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+goog.object.extend(exports, proto.helloworld);
diff --git a/examples/node/package.json b/examples/node/package.json
index d135df2..49ab74d 100644
--- a/examples/node/package.json
+++ b/examples/node/package.json
@@ -4,6 +4,7 @@
   "dependencies": {
     "async": "^1.5.2",
     "grpc": "0.13.0",
+    "google-protobuf": "*",
     "lodash": "^4.6.1",
     "minimist": "^1.2.0"
   }
diff --git a/grpc.gemspec b/grpc.gemspec
index f83b7d3..a9f0f68 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -24,10 +24,6 @@
   s.files += Dir.glob('include/grpc/**/*')
   s.test_files = Dir.glob('src/ruby/spec/**/*')
   s.bindir = 'src/ruby/bin'
-  %w(math noproto).each do |b|
-    s.executables += ["#{b}_client.rb", "#{b}_server.rb"]
-  end
-  s.executables += %w(grpc_ruby_interop_client grpc_ruby_interop_server)
   s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
diff --git a/package.json b/package.json
index 72731c0..5ed7f36 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
     "lib": "src/node/src"
   },
   "scripts": {
-    "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js",
+    "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js --exclude-path=src/node/.jshintignore",
     "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
     "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
     "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
@@ -35,6 +35,7 @@
   "devDependencies": {
     "async": "^1.5.0",
     "google-auth-library": "^0.9.2",
+    "google-protobuf": "^3.0.0-alpha.5",
     "istanbul": "^0.3.21",
     "jsdoc": "^3.3.2",
     "jshint": "^2.5.0",
@@ -72,5 +73,25 @@
     "binding.gyp"
   ],
   "main": "src/node/index.js",
-  "license": "BSD-3-Clause"
+  "license": "BSD-3-Clause",
+  "jshintConfig" : {
+    "bitwise": true,
+    "curly": true,
+    "eqeqeq": true,
+    "esnext": true,
+    "freeze": true,
+    "immed": true,
+    "indent": 2,
+    "latedef": "nofunc",
+    "maxlen": 80,
+    "mocha": true,
+    "newcap": true,
+    "node": true,
+    "noarg": true,
+    "quotmark": "single",
+    "strict": true,
+    "trailing": true,
+    "undef": true,
+    "unused": "vars"
+  }
 }
diff --git a/package.xml b/package.xml
index d192ebd..3ae810d 100644
--- a/package.xml
+++ b/package.xml
@@ -10,7 +10,7 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2016-03-01</date>
+ <date>2016-04-19</date>
  <time>16:06:07</time>
  <version>
   <release>0.14.0</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>BSD</license>
  <notes>
-- Increase unit test code coverage #5225
+- destroy grpc_byte_buffer after startBatch #6096
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -996,8 +996,8 @@
   </release>
   <release>
    <version>
-    <release>0.14.0</release>
-    <api>0.14.0</api>
+    <release>0.8.1</release>
+    <api>0.8.1</api>
    </version>
    <stability>
     <release>beta</release>
@@ -1009,5 +1009,20 @@
 - Increase unit test code coverage #5225
    </notes>
   </release>
+  <release>
+   <version>
+    <release>0.14.0</release>
+    <api>0.14.0</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>beta</api>
+   </stability>
+   <date>2016-04-19</date>
+   <license>BSD</license>
+   <notes>
+- destroy grpc_byte_buffer after startBatch #6096
+   </notes>
+  </release>
  </changelog>
 </package>
diff --git a/requirements.txt b/requirements.txt
index e3208e6..0ec0e75 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,8 @@
 # GRPC Python setup requirements
+coverage>=4.0
+cython>=0.23
 enum34>=1.0.4
 futures>=2.2.0
-cython>=0.23
-coverage>=4.0
+protobuf>=3.0.0a3
 six>=1.10
-wheel>=0.29
+wheel>=0.29
\ No newline at end of file
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index b133699..9319c41 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -86,7 +86,7 @@
   }
 }
 
-grpc::string GetHeaderPrologue(File *file, const Parameters &params) {
+grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -96,6 +96,7 @@
     vars["filename"] = file->filename();
     vars["filename_identifier"] = FilenameIdentifier(file->filename());
     vars["filename_base"] = file->filename_without_ext();
+    vars["message_header_ext"] = file->message_header_ext();
 
     printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
     printer->Print(vars,
@@ -104,7 +105,7 @@
     printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
     printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
     printer->Print(vars, "\n");
-    printer->Print(vars, "#include \"$filename_base$.pb.h\"\n");
+    printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
     printer->Print(vars, "\n");
   }
   return output;
@@ -794,8 +795,7 @@
   return output;
 }
 
-grpc::string GetHeaderEpilogue(File *file,
-                               const Parameters &params) {
+grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -821,8 +821,7 @@
   return output;
 }
 
-grpc::string GetSourcePrologue(File *file,
-                               const Parameters &params) {
+grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -831,13 +830,16 @@
 
     vars["filename"] = file->filename();
     vars["filename_base"] = file->filename_without_ext();
+    vars["message_header_ext"] = file->message_header_ext();
+    vars["service_header_ext"] = file->service_header_ext();
 
     printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
     printer->Print(vars,
                   "// If you make any local change, they will be lost.\n");
     printer->Print(vars, "// source: $filename$\n\n");
-    printer->Print(vars, "#include \"$filename_base$.pb.h\"\n");
-    printer->Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n");
+    printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+    printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
+    printer->Print(vars, file->additional_headers().c_str());
     printer->Print(vars, "\n");
   }
   return output;
@@ -1180,8 +1182,7 @@
   return output;
 }
 
-grpc::string GetSourceEpilogue(File *file,
-                               const Parameters &params) {
+grpc::string GetSourceEpilogue(File *file, const Parameters & /*params*/) {
   grpc::string temp;
 
   if (!file->package().empty()) {
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 99a60a2..953ddfd 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -106,8 +106,11 @@
 
   virtual grpc::string filename() const = 0;
   virtual grpc::string filename_without_ext() const = 0;
+  virtual grpc::string message_header_ext() const = 0;
+  virtual grpc::string service_header_ext() const = 0;
   virtual grpc::string package() const = 0;
   virtual std::vector<grpc::string> package_parts() const = 0;
+  virtual grpc::string additional_headers() const = 0;
 
   virtual int service_count() const = 0;
   virtual std::unique_ptr<const Service> service(int i) const = 0;
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index f703c64..e321c64 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -120,11 +120,16 @@
     return grpc_generator::StripProto(filename());
   }
 
+  grpc::string message_header_ext() const { return ".pb.h"; }
+  grpc::string service_header_ext() const { return ".grpc.pb.h"; }
+
   grpc::string package() const { return file_->package(); }
   std::vector<grpc::string> package_parts() const {
     return grpc_generator::tokenize(package(), ".");
   }
 
+  grpc::string additional_headers() const { return ""; }
+
   int service_count() const { return file_->service_count(); };
   std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
     return std::unique_ptr<const grpc_cpp_generator::Service> (
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 69e2738..4def6c5 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -350,10 +350,12 @@
 
 void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
   out->Print("// client stub\n");
+  out->Print("#pragma warning disable 0618\n");
   out->Print(
       "public class $name$ : ClientBase<$name$>, $interface$\n",
       "name", GetClientClassName(service),
       "interface", GetClientInterfaceName(service));
+  out->Print("#pragma warning restore 0618\n");
   out->Print("{\n");
   out->Indent();
 
@@ -480,10 +482,12 @@
                                bool use_server_class) {
   out->Print(
       "// creates service definition that can be registered with a server\n");
+  out->Print("#pragma warning disable 0618\n");
   out->Print(
       "public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
       "interface", use_server_class ? GetServerClassName(service) :
           GetServerInterfaceName(service));
+  out->Print("#pragma warning restore 0618\n");
   out->Print("{\n");
   out->Indent();
 
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index e1bb66a..3ed0500 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -52,6 +52,16 @@
   return false;
 }
 
+inline bool StripPrefix(grpc::string *name, const grpc::string &prefix) {
+  if (name->length() >= prefix.length()) {
+    if (name->substr(0, prefix.size()) == prefix) {
+      *name = name->substr(prefix.size());
+      return true;
+    }
+  }
+  return false;
+}
+
 inline grpc::string StripProto(grpc::string filename) {
   if (!StripSuffix(&filename, ".protodevel")) {
     StripSuffix(&filename, ".proto");
diff --git a/src/compiler/node_generator.cc b/src/compiler/node_generator.cc
new file mode 100644
index 0000000..822622c
--- /dev/null
+++ b/src/compiler/node_generator.cc
@@ -0,0 +1,277 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
+ * OWNER OR 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.
+ *
+ */
+
+#include <map>
+
+#include "src/compiler/config.h"
+#include "src/compiler/generator_helpers.h"
+#include "src/compiler/node_generator_helpers.h"
+
+using grpc::protobuf::FileDescriptor;
+using grpc::protobuf::ServiceDescriptor;
+using grpc::protobuf::MethodDescriptor;
+using grpc::protobuf::Descriptor;
+using grpc::protobuf::io::Printer;
+using grpc::protobuf::io::StringOutputStream;
+using std::map;
+
+namespace grpc_node_generator {
+namespace {
+
+// Returns the alias we assign to the module of the given .proto filename
+// when importing. Copied entirely from
+// github:google/protobuf/src/google/protobuf/compiler/js/js_generator.cc#L154
+grpc::string ModuleAlias(const grpc::string filename) {
+  // This scheme could technically cause problems if a file includes any 2 of:
+  //   foo/bar_baz.proto
+  //   foo_bar_baz.proto
+  //   foo_bar/baz.proto
+  //
+  // We'll worry about this problem if/when we actually see it.  This name isn't
+  // exposed to users so we can change it later if we need to.
+  grpc::string basename = grpc_generator::StripProto(filename);
+  basename = grpc_generator::StringReplace(basename, "-", "$");
+  basename = grpc_generator::StringReplace(basename, "/", "_");
+  return basename + "_pb";
+}
+
+// Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript
+// message file foo/bar/baz.js
+grpc::string GetJSMessageFilename(const grpc::string& filename) {
+  grpc::string name = filename;
+  return grpc_generator::StripProto(name) + "_pb.js";
+}
+
+// Given a filename like foo/bar/baz.proto, returns the root directory
+// path ../../
+grpc::string GetRootPath(const grpc::string& filename) {
+  size_t slashes = std::count(filename.begin(), filename.end(), '/');
+  if (slashes == 0) {
+    return "./";
+  }
+  grpc::string result = "";
+  for (size_t i = 0; i < slashes; i++) {
+    result += "../";
+  }
+  return result;
+}
+
+// Return the relative path to load to_file from the directory containing
+// from_file, assuming that both paths are relative to the same directory
+grpc::string GetRelativePath(const grpc::string& from_file,
+                             const grpc::string& to_file) {
+  return GetRootPath(from_file) + to_file;
+}
+
+/* Finds all message types used in all services in the file, and returns them
+ * as a map of fully qualified message type name to message descriptor */
+map<grpc::string, const Descriptor*> GetAllMessages(const FileDescriptor *file) {
+  map<grpc::string, const Descriptor*> message_types;
+  for (int service_num = 0; service_num < file->service_count(); service_num++) {
+    const ServiceDescriptor* service = file->service(service_num);
+    for (int method_num = 0; method_num < service->method_count(); method_num++) {
+      const MethodDescriptor* method = service->method(method_num);
+      const Descriptor* input_type = method->input_type();
+      const Descriptor* output_type = method->output_type();
+      message_types[input_type->name()] = input_type;
+      message_types[output_type->name()] = output_type;
+    }
+  }
+  return message_types;
+}
+
+grpc::string MessageIdentifierName(const grpc::string& name) {
+  return grpc_generator::StringReplace(name, ".", "_");
+}
+
+grpc::string NodeObjectPath(const Descriptor *descriptor) {
+  grpc::string module_alias = ModuleAlias(descriptor->file()->name());
+  grpc::string name = descriptor->name();
+  grpc_generator::StripPrefix(&name, descriptor->file()->package() + ".");
+  return module_alias + "." + name;
+}
+
+// Prints out the message serializer and deserializer functions
+void PrintMessageTransformer(const Descriptor *descriptor, Printer *out) {
+  map<grpc::string, grpc::string> template_vars;
+  template_vars["identifier_name"] = MessageIdentifierName(descriptor->name());
+  template_vars["name"] = descriptor->name();
+  template_vars["node_name"] = NodeObjectPath(descriptor);
+  // Print the serializer
+  out->Print(template_vars, "function serialize_$identifier_name$(arg) {\n");
+  out->Indent();
+  out->Print(template_vars, "if (!(arg instanceof $node_name$)) {\n");
+  out->Indent();
+  out->Print(template_vars,
+             "throw new Error('Expected argument of type $name$');\n");
+  out->Outdent();
+  out->Print("}\n");
+  out->Print("return new Buffer(arg.serializeBinary());\n");
+  out->Outdent();
+  out->Print("}\n\n");
+
+  // Print the deserializer
+  out->Print(template_vars,
+             "function deserialize_$identifier_name$(buffer_arg) {\n");
+  out->Indent();
+  out->Print(
+      template_vars,
+      "return $node_name$.deserializeBinary(new Uint8Array(buffer_arg));\n");
+  out->Outdent();
+  out->Print("}\n\n");
+}
+
+void PrintMethod(const MethodDescriptor *method, Printer *out) {
+  const Descriptor *input_type = method->input_type();
+  const Descriptor *output_type = method->output_type();
+  map<grpc::string, grpc::string> vars;
+  vars["service_name"] = method->service()->full_name();
+  vars["name"] = method->name();
+  vars["input_type"] = NodeObjectPath(input_type);
+  vars["input_type_id"] = MessageIdentifierName(input_type->name());
+  vars["output_type"] = NodeObjectPath(output_type);
+  vars["output_type_id"] = MessageIdentifierName(output_type->name());
+  vars["client_stream"] = method->client_streaming() ? "true" : "false";
+  vars["server_stream"] = method->server_streaming() ? "true" : "false";
+  out->Print("{\n");
+  out->Indent();
+  out->Print(vars, "path: '/$service_name$/$name$',\n");
+  out->Print(vars, "requestStream: $client_stream$,\n");
+  out->Print(vars, "responseStream: $server_stream$,\n");
+  out->Print(vars, "requestType: $input_type$,\n");
+  out->Print(vars, "responseType: $output_type$,\n");
+  out->Print(vars, "requestSerialize: serialize_$input_type_id$,\n");
+  out->Print(vars, "requestDeserialize: deserialize_$input_type_id$,\n");
+  out->Print(vars, "responseSerialize: serialize_$output_type_id$,\n");
+  out->Print(vars, "responseDeserialize: deserialize_$output_type_id$,\n");
+  out->Outdent();
+  out->Print("}");
+}
+
+// Prints out the service descriptor object
+void PrintService(const ServiceDescriptor *service, Printer *out) {
+  map<grpc::string, grpc::string> template_vars;
+  template_vars["name"] = service->name();
+  out->Print(template_vars, "var $name$Service = exports.$name$Service = {\n");
+  out->Indent();
+  for (int i = 0; i < service->method_count(); i++) {
+    grpc::string method_name = grpc_generator::LowercaseFirstLetter(
+        service->method(i)->name());
+    out->Print("$method_name$: ",
+               "method_name", method_name);
+    PrintMethod(service->method(i), out);
+    out->Print(",\n");
+  }
+  out->Outdent();
+  out->Print("};\n\n");
+  out->Print(template_vars, "exports.$name$Client = "
+             "grpc.makeGenericClientConstructor($name$Service);\n");
+}
+
+}
+
+grpc::string GetImports(const FileDescriptor *file) {
+  grpc::string output;
+  {
+    StringOutputStream output_stream(&output);
+    Printer out(&output_stream, '$');
+
+    if (file->service_count() == 0) {
+      return output;
+    }
+
+    out.Print("// GENERATED CODE -- DO NOT EDIT!\n\n");
+
+    out.Print("'use strict';\n");
+
+    out.Print("var grpc = require('grpc');\n");
+    if (file->message_type_count() > 0) {
+      grpc::string file_path = GetRelativePath(file->name(),
+                                               GetJSMessageFilename(
+                                                   file->name()));
+      out.Print("var $module_alias$ = require('$file_path$');\n",
+                "module_alias", ModuleAlias(file->name()),
+                "file_path", file_path);
+    }
+
+    for (int i = 0; i < file->dependency_count(); i++) {
+      grpc::string file_path = GetRelativePath(
+          file->name(), GetJSMessageFilename(file->dependency(i)->name()));
+      out.Print("var $module_alias$ = require('$file_path$');\n",
+                "module_alias", ModuleAlias(file->dependency(i)->name()),
+                "file_path", file_path);
+    }
+    out.Print("\n");
+  }
+  return output;
+}
+
+grpc::string GetTransformers(const FileDescriptor *file) {
+  grpc::string output;
+  {
+    StringOutputStream output_stream(&output);
+    Printer out(&output_stream, '$');
+
+    if (file->service_count() == 0) {
+      return output;
+    }
+
+    map<grpc::string, const Descriptor*> messages = GetAllMessages(file);
+    for (std::map<grpc::string, const Descriptor*>::iterator it =
+             messages.begin();
+         it != messages.end(); it++) {
+      PrintMessageTransformer(it->second, &out);
+    }
+    out.Print("\n");
+  }
+  return output;
+}
+
+grpc::string GetServices(const FileDescriptor *file) {
+  grpc::string output;
+  {
+    StringOutputStream output_stream(&output);
+    Printer out(&output_stream, '$');
+
+    if (file->service_count() == 0) {
+      return output;
+    }
+
+    for (int i = 0; i < file->service_count(); i++) {
+      PrintService(file->service(i), &out);
+    }
+  }
+  return output;
+}
+
+}  // namespace grpc_node_generator
diff --git a/src/compiler/node_generator.h b/src/compiler/node_generator.h
new file mode 100644
index 0000000..249a0d0
--- /dev/null
+++ b/src/compiler/node_generator.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
+ * OWNER OR 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H
+
+#include "src/compiler/config.h"
+
+namespace grpc_node_generator {
+
+grpc::string GetImports(const grpc::protobuf::FileDescriptor *file);
+
+grpc::string GetTransformers(const grpc::protobuf::FileDescriptor *file);
+
+grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
+
+}  // namespace grpc_node_generator
+
+#endif  // GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H
diff --git a/src/compiler/node_generator_helpers.h b/src/compiler/node_generator_helpers.h
new file mode 100644
index 0000000..f41a2bc
--- /dev/null
+++ b/src/compiler/node_generator_helpers.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
+ * OWNER OR 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.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H
+#define GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H
+
+#include <algorithm>
+
+#include "src/compiler/config.h"
+#include "src/compiler/generator_helpers.h"
+
+namespace grpc_node_generator {
+
+inline grpc::string GetJSServiceFilename(const grpc::string& filename) {
+  return grpc_generator::StripProto(filename) + "_grpc_pb.js";
+}
+
+}  // namespace grpc_node_generator
+
+#endif  // GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H
diff --git a/src/compiler/node_plugin.cc b/src/compiler/node_plugin.cc
new file mode 100644
index 0000000..ac5ced3
--- /dev/null
+++ b/src/compiler/node_plugin.cc
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
+ * OWNER OR 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.
+ *
+ */
+
+// Generates Node gRPC service interface out of Protobuf IDL.
+
+#include <memory>
+
+#include "src/compiler/config.h"
+#include "src/compiler/node_generator.h"
+#include "src/compiler/node_generator_helpers.h"
+
+using grpc_node_generator::GetImports;
+using grpc_node_generator::GetJSServiceFilename;
+using grpc_node_generator::GetServices;
+using grpc_node_generator::GetTransformers;
+
+class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
+ public:
+  NodeGrpcGenerator() {}
+  ~NodeGrpcGenerator() {}
+
+  bool Generate(const grpc::protobuf::FileDescriptor *file,
+                const grpc::string &parameter,
+                grpc::protobuf::compiler::GeneratorContext *context,
+                grpc::string *error) const {
+    grpc::string code = GetImports(file) +
+        GetTransformers(file) +
+        GetServices(file);
+    if (code.size() == 0) {
+      return true;
+    }
+
+    // Get output file name
+    grpc::string file_name = GetJSServiceFilename(file->name());
+
+    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
+        context->Open(file_name));
+    grpc::protobuf::io::CodedOutputStream coded_out(output.get());
+    coded_out.WriteRaw(code.data(), code.size());
+    return true;
+  }
+};
+
+int main(int argc, char *argv[]) {
+  NodeGrpcGenerator generator;
+  return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
+}
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
index 779efbb..5847ec9 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -386,10 +386,18 @@
   for (s = shard->strs[idx]; s; s = s->bucket_next) {
     if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
         0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
-      GRPC_MDSTR_REF((grpc_mdstr *)s);
-      gpr_mu_unlock(&shard->mu);
-      GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
-      return (grpc_mdstr *)s;
+      if (gpr_atm_full_fetch_add(&s->refcnt, 1) == 0) {
+        /* If we get here, we've added a ref to something that was about to
+         * die - drop it immediately.
+         * The *only* possible path here (given the shard mutex) should be to
+         * drop from one ref back to zero - assert that with a CAS */
+        GPR_ASSERT(gpr_atm_rel_cas(&s->refcnt, 1, 0));
+        /* and treat this as if we were never here... sshhh */
+      } else {
+        gpr_mu_unlock(&shard->mu);
+        GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
+        return (grpc_mdstr *)s;
+      }
     }
   }
 
@@ -397,7 +405,7 @@
   if (length + 1 < GPR_SLICE_INLINED_SIZE) {
     /* string data goes directly into the slice */
     s = gpr_malloc(sizeof(internal_string));
-    gpr_atm_rel_store(&s->refcnt, 2);
+    gpr_atm_rel_store(&s->refcnt, 1);
     s->slice.refcount = NULL;
     memcpy(s->slice.data.inlined.bytes, buf, length);
     s->slice.data.inlined.bytes[length] = 0;
@@ -406,7 +414,7 @@
     /* string data goes after the internal_string header, and we +1 for null
        terminator */
     s = gpr_malloc(sizeof(internal_string) + length + 1);
-    gpr_atm_rel_store(&s->refcnt, 2);
+    gpr_atm_rel_store(&s->refcnt, 1);
     s->refcount.ref = slice_ref;
     s->refcount.unref = slice_unref;
     s->slice.refcount = &s->refcount;
@@ -675,20 +683,19 @@
 grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
   internal_string *s = (internal_string *)gs;
   if (is_mdstr_static(gs)) return gs;
-  GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0);
+  GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) > 0);
   return gs;
 }
 
 void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
   internal_string *s = (internal_string *)gs;
   if (is_mdstr_static(gs)) return;
-  if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
+  if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
     strtab_shard *shard =
         &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
     gpr_mu_lock(&shard->mu);
-    if (1 == gpr_atm_no_barrier_load(&s->refcnt)) {
-      internal_destroy_string(shard, s);
-    }
+    GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt));
+    internal_destroy_string(shard, s);
     gpr_mu_unlock(&shard->mu);
   }
 }
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
index 8a26bd8..f5c44fd 100644
--- a/src/csharp/Grpc.Core/Version.cs
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -33,5 +33,6 @@
 
 using System.Reflection;
 
-// The current version of gRPC C#.
 [assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentAssemblyVersion)]
+[assembly: AssemblyFileVersion(Grpc.Core.VersionInfo.CurrentAssemblyFileVersion)]
+[assembly: AssemblyInformationalVersion(Grpc.Core.VersionInfo.CurrentVersion)]
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 9014a13..f7a9cb9 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -35,13 +35,20 @@
 {
     /// <summary>
     /// Provides info about current version of gRPC.
+    /// See https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/
+    /// for rationale about assembly versioning.
     /// </summary>
     public static class VersionInfo
     {
         /// <summary>
-        /// Current version of gRPC C# assemblies
+        /// Current <c>AssemblyVersion</c> attribute of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyVersion = "0.14.0.0";
+        public const string CurrentAssemblyVersion = "1.0.0.0";
+
+        /// <summary>
+        /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
+        /// </summary>
+        public const string CurrentAssemblyFileVersion = "0.14.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index f3bb0d1..1a6482d 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -103,7 +103,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class MathClient : ClientBase<MathClient>, IMathClient
+    #pragma warning restore 0618
     {
       public MathClient(Channel channel) : base(channel)
       {
@@ -167,7 +169,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IMath serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_Div, serviceImpl.Div)
@@ -177,7 +181,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(MathBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_Div, serviceImpl.Div)
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index 72e11cc..e7f7797 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -56,7 +56,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class HealthClient : ClientBase<HealthClient>, IHealthClient
+    #pragma warning restore 0618
     {
       public HealthClient(Channel channel) : base(channel)
       {
@@ -96,14 +98,18 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IHealth serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_Check, serviceImpl.Check).Build();
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(HealthBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_Check, serviceImpl.Check).Build();
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index cc01ae9..11c1572 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -72,7 +72,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class MetricsServiceClient : ClientBase<MetricsServiceClient>, IMetricsServiceClient
+    #pragma warning restore 0618
     {
       public MetricsServiceClient(Channel channel) : base(channel)
       {
@@ -120,7 +122,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IMetricsService serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_GetAllGauges, serviceImpl.GetAllGauges)
@@ -128,7 +132,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(MetricsServiceBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_GetAllGauges, serviceImpl.GetAllGauges)
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index 46b16cf..18cf067 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -71,7 +71,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>, IBenchmarkServiceClient
+    #pragma warning restore 0618
     {
       public BenchmarkServiceClient(Channel channel) : base(channel)
       {
@@ -119,7 +121,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
@@ -127,7 +131,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(BenchmarkServiceBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
@@ -241,7 +247,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class WorkerServiceClient : ClientBase<WorkerServiceClient>, IWorkerServiceClient
+    #pragma warning restore 0618
     {
       public WorkerServiceClient(Channel channel) : base(channel)
       {
@@ -313,7 +321,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_RunServer, serviceImpl.RunServer)
@@ -323,7 +333,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(WorkerServiceBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_RunServer, serviceImpl.RunServer)
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 31746cb..3b915f6 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -138,7 +138,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class TestServiceClient : ClientBase<TestServiceClient>, ITestServiceClient
+    #pragma warning restore 0618
     {
       public TestServiceClient(Channel channel) : base(channel)
       {
@@ -226,7 +228,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(ITestService serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall)
@@ -238,7 +242,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(TestServiceBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall)
@@ -303,7 +309,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>, IUnimplementedServiceClient
+    #pragma warning restore 0618
     {
       public UnimplementedServiceClient(Channel channel) : base(channel)
       {
@@ -343,14 +351,18 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(UnimplementedServiceBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
@@ -429,7 +441,9 @@
     }
 
     // client stub
+    #pragma warning disable 0618
     public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>, IReconnectServiceClient
+    #pragma warning restore 0618
     {
       public ReconnectServiceClient(Channel channel) : base(channel)
       {
@@ -485,7 +499,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_Start, serviceImpl.Start)
@@ -493,7 +509,9 @@
     }
 
     // creates service definition that can be registered with a server
+    #pragma warning disable 0618
     public static ServerServiceDefinition BindService(ReconnectServiceBase serviceImpl)
+    #pragma warning restore 0618
     {
       return ServerServiceDefinition.CreateBuilder(__ServiceName)
           .AddMethod(__Method_Start, serviceImpl.Start)
diff --git a/src/node/.gitignore b/src/node/.gitignore
deleted file mode 100644
index e3fbd98..0000000
--- a/src/node/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-build
-node_modules
diff --git a/src/node/.jshintignore b/src/node/.jshintignore
new file mode 100644
index 0000000..0a73e1e
--- /dev/null
+++ b/src/node/.jshintignore
@@ -0,0 +1 @@
+**/*_pb.js
\ No newline at end of file
diff --git a/src/node/.jshintrc b/src/node/.jshintrc
deleted file mode 100644
index 8237e0d..0000000
--- a/src/node/.jshintrc
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "bitwise": true,
-  "curly": true,
-  "eqeqeq": true,
-  "esnext": true,
-  "freeze": true,
-  "immed": true,
-  "indent": 2,
-  "latedef": "nofunc",
-  "maxlen": 80,
-  "newcap": true,
-  "node": true,
-  "noarg": true,
-  "quotmark": "single",
-  "strict": true,
-  "trailing": true,
-  "undef": true,
-  "unused": "vars",
-  "globals": {
-    /* Mocha-provided globals */
-    "describe": false,
-    "it": false,
-    "before": false,
-    "beforeEach": false,
-    "after": false,
-    "afterEach": false
-  }
-}
diff --git a/src/node/test/math/math_grpc_pb.js b/src/node/test/math/math_grpc_pb.js
new file mode 100644
index 0000000..083ed66
--- /dev/null
+++ b/src/node/test/math/math_grpc_pb.js
@@ -0,0 +1,99 @@
+// GENERATED CODE -- DO NOT EDIT!
+
+'use strict';
+var grpc = require('grpc');
+var math_pb = require('./math_pb.js');
+
+function serialize_DivArgs(arg) {
+  if (!(arg instanceof math_pb.DivArgs)) {
+    throw new Error('Expected argument of type DivArgs');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_DivArgs(buffer_arg) {
+  return math_pb.DivArgs.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_DivReply(arg) {
+  if (!(arg instanceof math_pb.DivReply)) {
+    throw new Error('Expected argument of type DivReply');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_DivReply(buffer_arg) {
+  return math_pb.DivReply.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_FibArgs(arg) {
+  if (!(arg instanceof math_pb.FibArgs)) {
+    throw new Error('Expected argument of type FibArgs');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_FibArgs(buffer_arg) {
+  return math_pb.FibArgs.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+function serialize_Num(arg) {
+  if (!(arg instanceof math_pb.Num)) {
+    throw new Error('Expected argument of type Num');
+  }
+  return new Buffer(arg.serializeBinary());
+}
+
+function deserialize_Num(buffer_arg) {
+  return math_pb.Num.deserializeBinary(new Uint8Array(buffer_arg));
+}
+
+
+var MathService = exports.MathService = {
+  div: {
+    path: '/math.Math/Div',
+    requestStream: false,
+    responseStream: false,
+    requestType: math_pb.DivArgs,
+    responseType: math_pb.DivReply,
+    requestSerialize: serialize_DivArgs,
+    requestDeserialize: deserialize_DivArgs,
+    responseSerialize: serialize_DivReply,
+    responseDeserialize: deserialize_DivReply,
+  },
+  divMany: {
+    path: '/math.Math/DivMany',
+    requestStream: true,
+    responseStream: true,
+    requestType: math_pb.DivArgs,
+    responseType: math_pb.DivReply,
+    requestSerialize: serialize_DivArgs,
+    requestDeserialize: deserialize_DivArgs,
+    responseSerialize: serialize_DivReply,
+    responseDeserialize: deserialize_DivReply,
+  },
+  fib: {
+    path: '/math.Math/Fib',
+    requestStream: false,
+    responseStream: true,
+    requestType: math_pb.FibArgs,
+    responseType: math_pb.Num,
+    requestSerialize: serialize_FibArgs,
+    requestDeserialize: deserialize_FibArgs,
+    responseSerialize: serialize_Num,
+    responseDeserialize: deserialize_Num,
+  },
+  sum: {
+    path: '/math.Math/Sum',
+    requestStream: true,
+    responseStream: false,
+    requestType: math_pb.Num,
+    responseType: math_pb.Num,
+    requestSerialize: serialize_Num,
+    requestDeserialize: deserialize_Num,
+    responseSerialize: serialize_Num,
+    responseDeserialize: deserialize_Num,
+  },
+};
+
+exports.MathClient = grpc.makeGenericClientConstructor(MathService);
diff --git a/src/node/test/math/math_pb.js b/src/node/test/math/math_pb.js
new file mode 100644
index 0000000..3489143
--- /dev/null
+++ b/src/node/test/math/math_pb.js
@@ -0,0 +1,866 @@
+/**
+ * @fileoverview
+ * @enhanceable
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.math.DivArgs', null, global);
+goog.exportSymbol('proto.math.DivReply', null, global);
+goog.exportSymbol('proto.math.FibArgs', null, global);
+goog.exportSymbol('proto.math.FibReply', null, global);
+goog.exportSymbol('proto.math.Num', null, global);
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.math.DivArgs = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.math.DivArgs, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.math.DivArgs.displayName = 'proto.math.DivArgs';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.math.DivArgs.prototype.toObject = function(opt_includeInstance) {
+  return proto.math.DivArgs.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.math.DivArgs} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.math.DivArgs.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    dividend: msg.getDividend(),
+    divisor: msg.getDivisor()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.math.DivArgs}
+ */
+proto.math.DivArgs.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.math.DivArgs;
+  return proto.math.DivArgs.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.math.DivArgs} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.math.DivArgs}
+ */
+proto.math.DivArgs.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setDividend(value);
+      break;
+    case 2:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setDivisor(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.math.DivArgs} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.DivArgs.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.math.DivArgs.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.DivArgs.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getDividend();
+  if (f !== 0) {
+    writer.writeInt64(
+      1,
+      f
+    );
+  }
+  f = this.getDivisor();
+  if (f !== 0) {
+    writer.writeInt64(
+      2,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.math.DivArgs} The clone.
+ */
+proto.math.DivArgs.prototype.cloneMessage = function() {
+  return /** @type {!proto.math.DivArgs} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional int64 dividend = 1;
+ * @return {number}
+ */
+proto.math.DivArgs.prototype.getDividend = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
+};
+
+
+/** @param {number} value  */
+proto.math.DivArgs.prototype.setDividend = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional int64 divisor = 2;
+ * @return {number}
+ */
+proto.math.DivArgs.prototype.getDivisor = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0));
+};
+
+
+/** @param {number} value  */
+proto.math.DivArgs.prototype.setDivisor = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.math.DivReply = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.math.DivReply, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.math.DivReply.displayName = 'proto.math.DivReply';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.math.DivReply.prototype.toObject = function(opt_includeInstance) {
+  return proto.math.DivReply.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.math.DivReply} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.math.DivReply.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    quotient: msg.getQuotient(),
+    remainder: msg.getRemainder()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.math.DivReply}
+ */
+proto.math.DivReply.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.math.DivReply;
+  return proto.math.DivReply.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.math.DivReply} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.math.DivReply}
+ */
+proto.math.DivReply.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setQuotient(value);
+      break;
+    case 2:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setRemainder(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.math.DivReply} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.DivReply.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.math.DivReply.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.DivReply.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getQuotient();
+  if (f !== 0) {
+    writer.writeInt64(
+      1,
+      f
+    );
+  }
+  f = this.getRemainder();
+  if (f !== 0) {
+    writer.writeInt64(
+      2,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.math.DivReply} The clone.
+ */
+proto.math.DivReply.prototype.cloneMessage = function() {
+  return /** @type {!proto.math.DivReply} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional int64 quotient = 1;
+ * @return {number}
+ */
+proto.math.DivReply.prototype.getQuotient = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
+};
+
+
+/** @param {number} value  */
+proto.math.DivReply.prototype.setQuotient = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * optional int64 remainder = 2;
+ * @return {number}
+ */
+proto.math.DivReply.prototype.getRemainder = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0));
+};
+
+
+/** @param {number} value  */
+proto.math.DivReply.prototype.setRemainder = function(value) {
+  jspb.Message.setField(this, 2, value);
+};
+
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.math.FibArgs = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.math.FibArgs, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.math.FibArgs.displayName = 'proto.math.FibArgs';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.math.FibArgs.prototype.toObject = function(opt_includeInstance) {
+  return proto.math.FibArgs.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.math.FibArgs} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.math.FibArgs.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    limit: msg.getLimit()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.math.FibArgs}
+ */
+proto.math.FibArgs.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.math.FibArgs;
+  return proto.math.FibArgs.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.math.FibArgs} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.math.FibArgs}
+ */
+proto.math.FibArgs.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setLimit(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.math.FibArgs} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.FibArgs.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.math.FibArgs.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.FibArgs.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getLimit();
+  if (f !== 0) {
+    writer.writeInt64(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.math.FibArgs} The clone.
+ */
+proto.math.FibArgs.prototype.cloneMessage = function() {
+  return /** @type {!proto.math.FibArgs} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional int64 limit = 1;
+ * @return {number}
+ */
+proto.math.FibArgs.prototype.getLimit = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
+};
+
+
+/** @param {number} value  */
+proto.math.FibArgs.prototype.setLimit = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.math.Num = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.math.Num, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.math.Num.displayName = 'proto.math.Num';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.math.Num.prototype.toObject = function(opt_includeInstance) {
+  return proto.math.Num.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.math.Num} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.math.Num.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    num: msg.getNum()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.math.Num}
+ */
+proto.math.Num.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.math.Num;
+  return proto.math.Num.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.math.Num} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.math.Num}
+ */
+proto.math.Num.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setNum(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.math.Num} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.Num.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.math.Num.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.Num.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getNum();
+  if (f !== 0) {
+    writer.writeInt64(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.math.Num} The clone.
+ */
+proto.math.Num.prototype.cloneMessage = function() {
+  return /** @type {!proto.math.Num} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional int64 num = 1;
+ * @return {number}
+ */
+proto.math.Num.prototype.getNum = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
+};
+
+
+/** @param {number} value  */
+proto.math.Num.prototype.setNum = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.math.FibReply = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.math.FibReply, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  proto.math.FibReply.displayName = 'proto.math.FibReply';
+}
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto suitable for use in Soy templates.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.math.FibReply.prototype.toObject = function(opt_includeInstance) {
+  return proto.math.FibReply.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Whether to include the JSPB
+ *     instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.math.FibReply} msg The msg instance to transform.
+ * @return {!Object}
+ */
+proto.math.FibReply.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    count: msg.getCount()
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.math.FibReply}
+ */
+proto.math.FibReply.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.math.FibReply;
+  return proto.math.FibReply.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.math.FibReply} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.math.FibReply}
+ */
+proto.math.FibReply.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {number} */ (reader.readInt64());
+      msg.setCount(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Class method variant: serializes the given message to binary data
+ * (in protobuf wire format), writing to the given BinaryWriter.
+ * @param {!proto.math.FibReply} message
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.FibReply.serializeBinaryToWriter = function(message, writer) {
+  message.serializeBinaryToWriter(writer);
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.math.FibReply.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  this.serializeBinaryToWriter(writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format),
+ * writing to the given BinaryWriter.
+ * @param {!jspb.BinaryWriter} writer
+ */
+proto.math.FibReply.prototype.serializeBinaryToWriter = function (writer) {
+  var f = undefined;
+  f = this.getCount();
+  if (f !== 0) {
+    writer.writeInt64(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * Creates a deep clone of this proto. No data is shared with the original.
+ * @return {!proto.math.FibReply} The clone.
+ */
+proto.math.FibReply.prototype.cloneMessage = function() {
+  return /** @type {!proto.math.FibReply} */ (jspb.Message.cloneMessage(this));
+};
+
+
+/**
+ * optional int64 count = 1;
+ * @return {number}
+ */
+proto.math.FibReply.prototype.getCount = function() {
+  return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
+};
+
+
+/** @param {number} value  */
+proto.math.FibReply.prototype.setCount = function(value) {
+  jspb.Message.setField(this, 1, value);
+};
+
+
+goog.object.extend(exports, proto.math);
diff --git a/src/node/test/math/math_server.js b/src/node/test/math/math_server.js
index 9f67c52..fa05ed0 100644
--- a/src/node/test/math/math_server.js
+++ b/src/node/test/math/math_server.js
@@ -34,8 +34,8 @@
 'use strict';
 
 var grpc = require('../..');
-var math = grpc.load(__dirname + '/../../../proto/math/math.proto').math;
-
+var grpcMath = require('./math_grpc_pb');
+var math = require('./math_pb');
 
 /**
  * Server function for division. Provides the /Math/DivMany and /Math/Div
@@ -46,14 +46,16 @@
  */
 function mathDiv(call, cb) {
   var req = call.request;
+  var divisor = req.getDivisor();
+  var dividend = req.getDividend();
   // Unary + is explicit coersion to integer
-  if (+req.divisor === 0) {
+  if (req.getDivisor() === 0) {
     cb(new Error('cannot divide by zero'));
   } else {
-    cb(null, {
-      quotient: req.dividend / req.divisor,
-      remainder: req.dividend % req.divisor
-    });
+    var response = new math.DivReply();
+    response.setQuotient(Math.floor(dividend / divisor));
+    response.setRemainder(dividend % divisor);
+    cb(null, response);
   }
 }
 
@@ -67,7 +69,9 @@
   // Here, call is a standard writable Node object Stream
   var previous = 0, current = 1;
   for (var i = 0; i < stream.request.limit; i++) {
-    stream.write({num: current});
+    var response = new math.Num();
+    response.setNum(current);
+    stream.write(response);
     var temp = current;
     current += previous;
     previous = temp;
@@ -85,22 +89,26 @@
   // Here, call is a standard readable Node object Stream
   var sum = 0;
   call.on('data', function(data) {
-    sum += (+data.num);
+    sum += data.getNum();
   });
   call.on('end', function() {
-    cb(null, {num: sum});
+    var response = new math.Num();
+    response.setNum(sum);
+    cb(null, response);
   });
 }
 
 function mathDivMany(stream) {
   stream.on('data', function(div_args) {
-    if (+div_args.divisor === 0) {
+    var divisor = div_args.getDivisor();
+    var dividend = div_args.getDividend();
+    if (divisor === 0) {
       stream.emit('error', new Error('cannot divide by zero'));
     } else {
-      stream.write({
-        quotient: div_args.dividend / div_args.divisor,
-        remainder: div_args.dividend % div_args.divisor
-      });
+      var response = new math.DivReply();
+      response.setQuotient(Math.floor(dividend / divisor));
+      response.setRemainder(dividend % divisor);
+      stream.write(response);
     }
   });
   stream.on('end', function() {
@@ -110,7 +118,7 @@
 
 function getMathServer() {
   var server = new grpc.Server();
-  server.addProtoService(math.Math.service, {
+  server.addService(grpcMath.MathService, {
     div: mathDiv,
     fib: mathFib,
     sum: mathSum,
diff --git a/src/node/test/math/node_modules/grpc.js b/src/node/test/math/node_modules/grpc.js
new file mode 100644
index 0000000..17c8fd9
--- /dev/null
+++ b/src/node/test/math/node_modules/grpc.js
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
+ * OWNER OR 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.
+ *
+ */
+
+/* This exists solely to allow the generated code to import the grpc module
+ * without using a relative path */
+
+module.exports = require('../../..');
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index 3d44610..34c16e0 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -36,7 +36,8 @@
 var assert = require('assert');
 
 var grpc = require('..');
-var math = grpc.load(__dirname + '/../../proto/math/math.proto').math;
+var math = require('./math/math_pb');
+var MathClient = require('./math/math_grpc_pb').MathClient;
 
 /**
  * Client to use to make requests to a running server.
@@ -55,35 +56,41 @@
     var port_num = server.bind('0.0.0.0:0',
                                grpc.ServerCredentials.createInsecure());
     server.start();
-    math_client = new math.Math('localhost:' + port_num,
-                                grpc.credentials.createInsecure());
+    math_client = new MathClient('localhost:' + port_num,
+                                 grpc.credentials.createInsecure());
     done();
   });
   after(function() {
     server.forceShutdown();
   });
   it('should handle a single request', function(done) {
-    var arg = {dividend: 7, divisor: 4};
+    var arg = new math.DivArgs();
+    arg.setDividend(7);
+    arg.setDivisor(4);
     math_client.div(arg, function handleDivResult(err, value) {
       assert.ifError(err);
-      assert.equal(value.quotient, 1);
-      assert.equal(value.remainder, 3);
+      assert.equal(value.getQuotient(), 1);
+      assert.equal(value.getRemainder(), 3);
       done();
     });
   });
   it('should handle an error from a unary request', function(done) {
-    var arg = {dividend: 7, divisor: 0};
+    var arg = new math.DivArgs();
+    arg.setDividend(7);
+    arg.setDivisor(0);
     math_client.div(arg, function handleDivResult(err, value) {
       assert(err);
       done();
     });
   });
   it('should handle a server streaming request', function(done) {
-    var call = math_client.fib({limit: 7});
+    var arg = new math.FibArgs();
+    arg.setLimit(7);
+    var call = math_client.fib(arg);
     var expected_results = [1, 1, 2, 3, 5, 8, 13];
     var next_expected = 0;
     call.on('data', function checkResponse(value) {
-      assert.equal(value.num, expected_results[next_expected]);
+      assert.equal(value.getNum(), expected_results[next_expected]);
       next_expected += 1;
     });
     call.on('status', function checkStatus(status) {
@@ -94,10 +101,12 @@
   it('should handle a client streaming request', function(done) {
     var call = math_client.sum(function handleSumResult(err, value) {
       assert.ifError(err);
-      assert.equal(value.num, 21);
+      assert.equal(value.getNum(), 21);
     });
     for (var i = 0; i < 7; i++) {
-      call.write({'num': i});
+      var arg = new math.Num();
+      arg.setNum(i);
+      call.write(arg);
     }
     call.end();
     call.on('status', function checkStatus(status) {
@@ -107,8 +116,8 @@
   });
   it('should handle a bidirectional streaming request', function(done) {
     function checkResponse(index, value) {
-      assert.equal(value.quotient, index);
-      assert.equal(value.remainder, 1);
+      assert.equal(value.getQuotient(), index);
+      assert.equal(value.getRemainder(), 1);
     }
     var call = math_client.divMany();
     var response_index = 0;
@@ -117,7 +126,10 @@
       response_index += 1;
     });
     for (var i = 0; i < 7; i++) {
-      call.write({dividend: 2 * i + 1, divisor: 2});
+      var arg = new math.DivArgs();
+      arg.setDividend(2 * i + 1);
+      arg.setDivisor(2);
+      call.write(arg);
     }
     call.end();
     call.on('status', function checkStatus(status) {
@@ -131,7 +143,10 @@
       assert.fail(value, undefined, 'Unexpected data response on failing call',
                   '!=');
     });
-    call.write({dividend: 7, divisor: 0});
+    var arg = new math.DivArgs();
+    arg.setDividend(7);
+    arg.setDivisor(0);
+    call.write(arg);
     call.end();
     call.on('error', function checkStatus(status) {
       done();
diff --git a/src/python/.gitignore b/src/python/.gitignore
new file mode 100644
index 0000000..f158efa
--- /dev/null
+++ b/src/python/.gitignore
@@ -0,0 +1 @@
+gens/
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 9e74570..295dab2 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -50,6 +50,9 @@
 import support
 
 PYTHON_STEM = os.path.dirname(os.path.abspath(__file__))
+GRPC_STEM = os.path.abspath(PYTHON_STEM + '../../../../')
+PROTO_STEM = os.path.join(GRPC_STEM, 'src', 'proto')
+PROTO_GEN_STEM = os.path.join(GRPC_STEM, 'src', 'python', 'gens')
 
 CONF_PY_ADDENDUM = """
 extensions.append('sphinx.ext.napoleon')
@@ -157,30 +160,45 @@
     if not self.grpc_python_plugin_command:
       raise CommandError('could not find grpc_python_plugin '
                          '(protoc plugin for GRPC Python)')
+
+    if not os.path.exists(PROTO_GEN_STEM):
+      os.makedirs(PROTO_GEN_STEM)
+
     include_regex = re.compile(self.include)
     exclude_regex = re.compile(self.exclude) if self.exclude else None
     paths = []
-    root_directory = PYTHON_STEM
-    for walk_root, directories, filenames in os.walk(root_directory):
+    for walk_root, directories, filenames in os.walk(PROTO_STEM):
       for filename in filenames:
         path = os.path.join(walk_root, filename)
         if include_regex.match(path) and not (
             exclude_regex and exclude_regex.match(path)):
           paths.append(path)
-    command = [
-        self.protoc_command,
-        '--plugin=protoc-gen-python-grpc={}'.format(
-            self.grpc_python_plugin_command),
-        '-I {}'.format(root_directory),
-        '--python_out={}'.format(root_directory),
-        '--python-grpc_out={}'.format(root_directory),
-    ] + paths
-    try:
-      subprocess.check_output(' '.join(command), cwd=root_directory, shell=True,
-                              stderr=subprocess.STDOUT)
-    except subprocess.CalledProcessError as e:
-      raise CommandError('Command:\n{}\nMessage:\n{}\nOutput:\n{}'.format(
-          command, e.message, e.output))
+
+    # TODO(kpayson): It would be nice to do this in a batch command,
+    # but we currently have name conflicts in src/proto
+    for path in paths:
+      command = [
+          self.protoc_command,
+          '--plugin=protoc-gen-python-grpc={}'.format(
+              self.grpc_python_plugin_command),
+          '-I {}'.format(GRPC_STEM),
+          '--python_out={}'.format(PROTO_GEN_STEM),
+          '--python-grpc_out={}'.format(PROTO_GEN_STEM),
+      ] + [path]
+      try:
+        subprocess.check_output(' '.join(command), cwd=PYTHON_STEM, shell=True,
+                                stderr=subprocess.STDOUT)
+      except subprocess.CalledProcessError as e:
+        sys.stderr.write(
+            'warning: Command:\n{}\nMessage:\n{}\nOutput:\n{}'.format(
+                command, e.message, e.output))
+
+    # Generated proto directories dont include __init__.py, but
+    # these are needed for python package resolution
+    for walk_root, _, _ in os.walk(PROTO_GEN_STEM):
+      if walk_root != PROTO_GEN_STEM:
+        path = os.path.join(walk_root, '__init__.py')
+        open(path, 'a').close()
 
 
 class BuildProjectMetadata(setuptools.Command):
diff --git a/src/python/grpcio/tests/interop/_insecure_interop_test.py b/src/python/grpcio/tests/interop/_insecure_interop_test.py
index 00b49ab..91519b6 100644
--- a/src/python/grpcio/tests/interop/_insecure_interop_test.py
+++ b/src/python/grpcio/tests/interop/_insecure_interop_test.py
@@ -32,11 +32,11 @@
 import unittest
 
 from grpc.beta import implementations
+from src.proto.grpc.testing import test_pb2
 
 from tests.interop import _interop_test_case
 from tests.interop import methods
 from tests.interop import server
-from tests.interop import test_pb2
 
 
 class InsecureInteropTest(
diff --git a/src/python/grpcio/tests/interop/_secure_interop_test.py b/src/python/grpcio/tests/interop/_secure_interop_test.py
index 86d7e43..c61547b 100644
--- a/src/python/grpcio/tests/interop/_secure_interop_test.py
+++ b/src/python/grpcio/tests/interop/_secure_interop_test.py
@@ -32,11 +32,11 @@
 import unittest
 
 from grpc.beta import implementations
+from src.proto.grpc.testing import test_pb2
 
 from tests.interop import _interop_test_case
 from tests.interop import methods
 from tests.interop import resources
-from tests.interop import test_pb2
 
 from tests.unit.beta import test_utilities
 
diff --git a/src/python/grpcio/tests/interop/client.py b/src/python/grpcio/tests/interop/client.py
index 1d10d7e..db29eb4 100644
--- a/src/python/grpcio/tests/interop/client.py
+++ b/src/python/grpcio/tests/interop/client.py
@@ -33,10 +33,10 @@
 from oauth2client import client as oauth2client_client
 
 from grpc.beta import implementations
+from src.proto.grpc.testing import test_pb2
 
 from tests.interop import methods
 from tests.interop import resources
-from tests.interop import test_pb2
 from tests.unit.beta import test_utilities
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
diff --git a/src/python/grpcio/tests/interop/empty.proto b/src/python/grpcio/tests/interop/empty.proto
deleted file mode 100644
index 6d0eb93..0000000
--- a/src/python/grpcio/tests/interop/empty.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * 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.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
-// OWNER OR 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.
-
-syntax = "proto3";
-
-package grpc.testing;
-
-// An empty message that you can re-use to avoid defining duplicated empty
-// messages in your project. A typical example is to use it as argument or the
-// return value of a service API. For instance:
-//
-//   service Foo {
-//     rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
-//   };
-//
-message Empty {}
diff --git a/src/python/grpcio/tests/interop/messages.proto b/src/python/grpcio/tests/interop/messages.proto
deleted file mode 100644
index 193b6c4..0000000
--- a/src/python/grpcio/tests/interop/messages.proto
+++ /dev/null
@@ -1,167 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * 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.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
-// OWNER OR 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.
-
-// Message definitions to be used by integration test service definitions.
-
-syntax = "proto3";
-
-package grpc.testing;
-
-// The type of payload that should be returned.
-enum PayloadType {
-  // Compressable text format.
-  COMPRESSABLE = 0;
-
-  // Uncompressable binary format.
-  UNCOMPRESSABLE = 1;
-
-  // Randomly chosen from all other formats defined in this enum.
-  RANDOM = 2;
-}
-
-// Compression algorithms
-enum CompressionType {
-  // No compression
-  NONE = 0;
-  GZIP = 1;
-  DEFLATE = 2;
-}
-
-// A block of data, to simply increase gRPC message size.
-message Payload {
-  // The type of data in body.
-  PayloadType type = 1;
-  // Primary contents of payload.
-  bytes body = 2;
-}
-
-// A protobuf representation for grpc status. This is used by test
-// clients to specify a status that the server should attempt to return.
-message EchoStatus {
-  int32 code = 1;
-  string message = 2;
-}
-
-// Unary request.
-message SimpleRequest {
-  // Desired payload type in the response from the server.
-  // If response_type is RANDOM, server randomly chooses one from other formats.
-  PayloadType response_type = 1;
-
-  // Desired payload size in the response from the server.
-  // If response_type is COMPRESSABLE, this denotes the size before compression.
-  int32 response_size = 2;
-
-  // Optional input payload sent along with the request.
-  Payload payload = 3;
-
-  // Whether SimpleResponse should include username.
-  bool fill_username = 4;
-
-  // Whether SimpleResponse should include OAuth scope.
-  bool fill_oauth_scope = 5;
-
-  // Compression algorithm to be used by the server for the response (stream)
-  CompressionType response_compression = 6;
-
-  // Whether server should return a given status
-  EchoStatus response_status = 7;
-}
-
-// Unary response, as configured by the request.
-message SimpleResponse {
-  // Payload to increase message size.
-  Payload payload = 1;
-  // The user the request came from, for verifying authentication was
-  // successful when the client expected it.
-  string username = 2;
-  // OAuth scope.
-  string oauth_scope = 3;
-}
-
-// Client-streaming request.
-message StreamingInputCallRequest {
-  // Optional input payload sent along with the request.
-  Payload payload = 1;
-
-  // Not expecting any payload from the response.
-}
-
-// Client-streaming response.
-message StreamingInputCallResponse {
-  // Aggregated size of payloads received from the client.
-  int32 aggregated_payload_size = 1;
-}
-
-// Configuration for a particular response.
-message ResponseParameters {
-  // Desired payload sizes in responses from the server.
-  // If response_type is COMPRESSABLE, this denotes the size before compression.
-  int32 size = 1;
-
-  // Desired interval between consecutive responses in the response stream in
-  // microseconds.
-  int32 interval_us = 2;
-}
-
-// Server-streaming request.
-message StreamingOutputCallRequest {
-  // Desired payload type in the response from the server.
-  // If response_type is RANDOM, the payload from each response in the stream
-  // might be of different types. This is to simulate a mixed type of payload
-  // stream.
-  PayloadType response_type = 1;
-
-  // Configuration for each expected response message.
-  repeated ResponseParameters response_parameters = 2;
-
-  // Optional input payload sent along with the request.
-  Payload payload = 3;
-
-  // Compression algorithm to be used by the server for the response (stream)
-  CompressionType response_compression = 6;
-
-  // Whether server should return a given status
-  EchoStatus response_status = 7;
-}
-
-// Server-streaming response, as configured by the request and parameters.
-message StreamingOutputCallResponse {
-  // Payload to increase response size.
-  Payload payload = 1;
-}
-
-// For reconnect interop test only.
-// Server tells client whether its reconnects are following the spec and the
-// reconnect backoffs it saw.
-message ReconnectInfo {
-  bool passed = 1;
-  repeated int32 backoff_ms = 2;
-}
diff --git a/src/python/grpcio/tests/interop/methods.py b/src/python/grpcio/tests/interop/methods.py
index 0381033..67862ed 100644
--- a/src/python/grpcio/tests/interop/methods.py
+++ b/src/python/grpcio/tests/interop/methods.py
@@ -42,9 +42,9 @@
 from grpc.framework.common import cardinality
 from grpc.framework.interfaces.face import face
 
-from tests.interop import empty_pb2
-from tests.interop import messages_pb2
-from tests.interop import test_pb2
+from src.proto.grpc.testing import empty_pb2
+from src.proto.grpc.testing import messages_pb2
+from src.proto.grpc.testing import test_pb2
 
 _TIMEOUT = 7
 
diff --git a/src/python/grpcio/tests/interop/server.py b/src/python/grpcio/tests/interop/server.py
index 6dd55f0..ab2c3c7 100644
--- a/src/python/grpcio/tests/interop/server.py
+++ b/src/python/grpcio/tests/interop/server.py
@@ -34,10 +34,10 @@
 import time
 
 from grpc.beta import implementations
+from src.proto.grpc.testing import test_pb2
 
 from tests.interop import methods
 from tests.interop import resources
-from tests.interop import test_pb2
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
diff --git a/src/python/grpcio/tests/interop/test.proto b/src/python/grpcio/tests/interop/test.proto
deleted file mode 100644
index 9feecc0..0000000
--- a/src/python/grpcio/tests/interop/test.proto
+++ /dev/null
@@ -1,86 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * 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.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
-// OWNER OR 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.
-
-// An integration test service that covers all the method signature permutations
-// of unary/streaming requests/responses.
-
-syntax = "proto3";
-
-import "tests/interop/empty.proto";
-import "tests/interop/messages.proto";
-
-package grpc.testing;
-
-// A simple service to test the various types of RPCs and experiment with
-// performance with various types of payload.
-service TestService {
-  // One empty request followed by one empty response.
-  rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
-
-  // One request followed by one response.
-  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
-
-  // One request followed by a sequence of responses (streamed download).
-  // The server returns the payload with client desired type and sizes.
-  rpc StreamingOutputCall(StreamingOutputCallRequest)
-      returns (stream StreamingOutputCallResponse);
-
-  // A sequence of requests followed by one response (streamed upload).
-  // The server returns the aggregated size of client payload as the result.
-  rpc StreamingInputCall(stream StreamingInputCallRequest)
-      returns (StreamingInputCallResponse);
-
-  // A sequence of requests with each request served by the server immediately.
-  // As one request could lead to multiple responses, this interface
-  // demonstrates the idea of full duplexing.
-  rpc FullDuplexCall(stream StreamingOutputCallRequest)
-      returns (stream StreamingOutputCallResponse);
-
-  // A sequence of requests followed by a sequence of responses.
-  // The server buffers all the client requests and then serves them in order. A
-  // stream of responses are returned to the client when the server starts with
-  // first request.
-  rpc HalfDuplexCall(stream StreamingOutputCallRequest)
-      returns (stream StreamingOutputCallResponse);
-}
-
-
-// A simple service NOT implemented at servers so clients can test for
-// that case.
-service UnimplementedService {
-  // A call that no server should implement
-  rpc UnimplementedCall(grpc.testing.Empty) returns(grpc.testing.Empty);  
-}
-
-// A service used to control reconnect server.
-service ReconnectService {
-  rpc Start(grpc.testing.Empty) returns (grpc.testing.Empty);
-  rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo);
-}
diff --git a/src/ruby/bin/grpc_ruby_interop_client b/src/ruby/bin/grpc_ruby_interop_client
deleted file mode 100755
index e79fd33..0000000
--- a/src/ruby/bin/grpc_ruby_interop_client
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * 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.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
-# OWNER OR 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.
-
-# Provides a gem binary entry point for the interop client.
-require 'test/client'
diff --git a/src/ruby/bin/grpc_ruby_interop_server b/src/ruby/bin/grpc_ruby_interop_server
deleted file mode 100755
index 656a5f7..0000000
--- a/src/ruby/bin/grpc_ruby_interop_server
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * 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.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
-# OWNER OR 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.
-
-# Provides a gem binary entry point for the interop server
-require 'test/server'
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb
deleted file mode 100755
index 239083f..0000000
--- a/src/ruby/bin/interop/interop_client.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * 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.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
-# OWNER OR 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.
-
-# #######################################################################
-# DEPRECATED: The behaviour in this file has been moved to pb/test/client.rb
-#
-# This file remains to support existing tools and scripts that use it.
-# ######################################################################
-#
-# interop_client is a testing tool that accesses a gRPC interop testing
-# server and runs a test on it.
-#
-# Helps validate interoperation b/w different gRPC implementations.
-#
-# Usage: $ path/to/interop_client.rb --server_host=<hostname> \
-#                                    --server_port=<port> \
-#                                    --test_case=<testcase_name>
-
-this_dir = File.expand_path(File.dirname(__FILE__))
-pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
-$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
-
-require 'test/client'
diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb
deleted file mode 100755
index c6b0d00..0000000
--- a/src/ruby/bin/interop/interop_server.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * 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.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
-# OWNER OR 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.
-
-# #######################################################################
-# DEPRECATED: The behaviour in this file has been moved to pb/test/server.rb
-#
-# This file remains to support existing tools and scripts that use it.
-# ######################################################################
-#
-# interop_server is a Testing app that runs a gRPC interop testing server.
-#
-# It helps validate interoperation b/w gRPC in different environments
-#
-# Helps validate interoperation b/w different gRPC implementations.
-#
-# Usage: $ path/to/interop_server.rb --port
-
-this_dir = File.expand_path(File.dirname(__FILE__))
-pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb')
-$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
-
-require 'test/server'
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index f5fdbb2..48c49a2 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -214,6 +214,35 @@
   return res;
 }
 
+/* Called to obtain the x509 cert of an authenticated peer. */
+static VALUE grpc_rb_call_get_peer_cert(VALUE self) {
+  grpc_call *call = NULL;
+  VALUE res = Qnil;
+  grpc_auth_context *ctx = NULL;
+  TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
+
+  ctx = grpc_call_auth_context(call);
+
+  if (!ctx || !grpc_auth_context_peer_is_authenticated(ctx)) {
+    return Qnil;
+  }
+
+  {
+    grpc_auth_property_iterator it =
+        grpc_auth_context_find_properties_by_name(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME);
+    const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
+    if (prop == NULL) {
+      return Qnil;
+    }
+
+    res = rb_str_new2(prop->value);
+  }
+
+  grpc_auth_context_release(ctx);
+
+  return res;
+}
+
 /*
   call-seq:
   status = call.status
@@ -861,6 +890,7 @@
   rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4);
   rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0);
   rb_define_method(grpc_rb_cCall, "peer", grpc_rb_call_get_peer, 0);
+  rb_define_method(grpc_rb_cCall, "peer_cert", grpc_rb_call_get_peer_cert, 0);
   rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0);
   rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1);
   rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
diff --git a/src/ruby/lib/grpc.rb b/src/ruby/lib/grpc.rb
index 4e23cd7..a56c49f 100644
--- a/src/ruby/lib/grpc.rb
+++ b/src/ruby/lib/grpc.rb
@@ -32,13 +32,13 @@
   ENV['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH'] = ssl_roots_path
 end
 
-require 'grpc/errors'
-require 'grpc/grpc'
-require 'grpc/logconfig'
-require 'grpc/notifier'
-require 'grpc/version'
-require 'grpc/core/time_consts'
-require 'grpc/generic/active_call'
-require 'grpc/generic/client_stub'
-require 'grpc/generic/service'
-require 'grpc/generic/rpc_server'
+require_relative 'grpc/errors'
+require_relative 'grpc/grpc'
+require_relative 'grpc/logconfig'
+require_relative 'grpc/notifier'
+require_relative 'grpc/version'
+require_relative 'grpc/core/time_consts'
+require_relative 'grpc/generic/active_call'
+require_relative 'grpc/generic/client_stub'
+require_relative 'grpc/generic/service'
+require_relative 'grpc/generic/rpc_server'
diff --git a/src/ruby/lib/grpc/core/time_consts.rb b/src/ruby/lib/grpc/core/time_consts.rb
index 3b8c2da..5be7ed2 100644
--- a/src/ruby/lib/grpc/core/time_consts.rb
+++ b/src/ruby/lib/grpc/core/time_consts.rb
@@ -27,7 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'grpc/grpc'
+require_relative '../grpc'
 
 # GRPC contains the General RPC module.
 module GRPC
diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb
index 1d7588c..a1dd1e3 100644
--- a/src/ruby/lib/grpc/errors.rb
+++ b/src/ruby/lib/grpc/errors.rb
@@ -27,7 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'grpc/grpc'
+require_relative './grpc'
 
 # GRPC contains the General RPC module.
 module GRPC
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index e80d24e..ecf3cc3 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'forwardable'
-require 'grpc/generic/bidi_call'
+require_relative 'bidi_call'
 
 class Struct
   # BatchResult is the struct returned by calls to call#start_batch.
@@ -59,7 +59,8 @@
     include Core::CallOps
     extend Forwardable
     attr_reader(:deadline)
-    def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=
+    def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=,
+                   :peer, :peer_cert
 
     # client_invoke begins a client invocation.
     #
@@ -472,7 +473,7 @@
     # SingleReqView limits access to an ActiveCall's methods for use in server
     # handlers that receive just one request.
     SingleReqView = view_class(:cancelled, :deadline, :metadata,
-                               :output_metadata)
+                               :output_metadata, :peer, :peer_cert)
 
     # MultiReqView limits access to an ActiveCall's methods for use in
     # server client_streamer handlers.
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 6b9b785..1f6d5f3 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'forwardable'
-require 'grpc/grpc'
+require_relative '../grpc'
 
 # GRPC contains the General RPC module.
 module GRPC
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index a6bb92d..68e167a 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -27,8 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'grpc/generic/active_call'
-require 'grpc/version'
+require_relative 'active_call'
+require_relative '../version'
 
 # GRPC contains the General RPC module.
 module GRPC
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index dd90d8d..cc21ffd 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -27,7 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'grpc/grpc'
+require_relative '../grpc'
 
 # GRPC contains the General RPC module.
 module GRPC
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 5ba77db..7f3a38a 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -27,9 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'grpc/grpc'
-require 'grpc/generic/active_call'
-require 'grpc/generic/service'
+require_relative '../grpc'
+require_relative 'active_call'
+require_relative 'service'
 require 'thread'
 
 # A global that contains signals the gRPC servers should respond to.
@@ -332,10 +332,15 @@
     # the current thread to terminate it.
     def run_till_terminated
       GRPC.trap_signals
-      t = Thread.new { run }
+      stopped = false
+      t = Thread.new do
+        run
+        stopped = true
+      end
       wait_till_running
       loop do
         sleep SIGNAL_CHECK_PERIOD
+        break if stopped
         break unless GRPC.handle_signals
       end
       stop
@@ -434,7 +439,6 @@
         begin
           an_rpc = @server.request_call(@cq, loop_tag, INFINITE_FUTURE)
           break if (!an_rpc.nil?) && an_rpc.call.nil?
-
           active_call = new_active_server_call(an_rpc)
           unless active_call.nil?
             @pool.schedule(active_call) do |ac|
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 410e1ad..8e940b5 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -27,8 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'grpc/generic/client_stub'
-require 'grpc/generic/rpc_desc'
+require_relative 'client_stub'
+require_relative 'rpc_desc'
 
 # GRPC contains the General RPC module.
 module GRPC
diff --git a/src/ruby/lib/grpc/grpc.rb b/src/ruby/lib/grpc/grpc.rb
index 250f6dd..b60a828 100644
--- a/src/ruby/lib/grpc/grpc.rb
+++ b/src/ruby/lib/grpc/grpc.rb
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 begin
-  require "grpc/#{RUBY_VERSION.sub(/\.\d$/, '')}/grpc_c"
+  require_relative "#{RUBY_VERSION.sub(/\.\d$/, '')}/grpc_c"
 rescue LoadError
-  require 'grpc/grpc_c'
+  require_relative 'grpc_c'
 end
diff --git a/src/ruby/pb/grpc/testing/metrics.rb b/src/ruby/pb/grpc/testing/metrics.rb
new file mode 100644
index 0000000..3b3c8cd
--- /dev/null
+++ b/src/ruby/pb/grpc/testing/metrics.rb
@@ -0,0 +1,28 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: grpc/testing/metrics.proto
+
+require 'google/protobuf'
+
+Google::Protobuf::DescriptorPool.generated_pool.build do
+  add_message "grpc.testing.GaugeResponse" do
+    optional :name, :string, 1
+    oneof :value do
+      optional :long_value, :int64, 2
+      optional :double_value, :double, 3
+      optional :string_value, :string, 4
+    end
+  end
+  add_message "grpc.testing.GaugeRequest" do
+    optional :name, :string, 1
+  end
+  add_message "grpc.testing.EmptyMessage" do
+  end
+end
+
+module Grpc
+  module Testing
+    GaugeResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GaugeResponse").msgclass
+    GaugeRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.GaugeRequest").msgclass
+    EmptyMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EmptyMessage").msgclass
+  end
+end
diff --git a/src/ruby/pb/grpc/testing/metrics_services.rb b/src/ruby/pb/grpc/testing/metrics_services.rb
new file mode 100644
index 0000000..f5778bb
--- /dev/null
+++ b/src/ruby/pb/grpc/testing/metrics_services.rb
@@ -0,0 +1,27 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# Source: grpc/testing/metrics.proto for package 'grpc.testing'
+
+require 'grpc'
+require 'grpc/testing/metrics'
+
+module Grpc
+  module Testing
+    module MetricsService
+
+      # TODO: add proto service documentation here
+      class Service
+
+        include GRPC::GenericService
+
+        self.marshal_class_method = :encode
+        self.unmarshal_class_method = :decode
+        self.service_name = 'grpc.testing.MetricsService'
+
+        rpc :GetAllGauges, EmptyMessage, stream(GaugeResponse)
+        rpc :GetGauge, GaugeRequest, GaugeResponse
+      end
+
+      Stub = Service.rpc_stub_class
+    end
+  end
+end
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index 2f83e67..95b059a 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -38,23 +38,23 @@
 #                            --server_port=<port> \
 #                            --test_case=<testcase_name>
 
+# These lines are required for the generated files to load grpc
 this_dir = File.expand_path(File.dirname(__FILE__))
 lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
-pb_dir = File.dirname(File.dirname(this_dir))
+pb_dir = File.dirname(this_dir)
 $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
 $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
-$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
 
 require 'optparse'
 require 'logger'
 
-require 'grpc'
+require_relative '../../lib/grpc'
 require 'googleauth'
 require 'google/protobuf'
 
-require 'test/proto/empty'
-require 'test/proto/messages'
-require 'test/proto/test_services'
+require_relative 'proto/empty'
+require_relative 'proto/messages'
+require_relative 'proto/test_services'
 
 AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
 
@@ -208,12 +208,10 @@
   def empty_unary
     resp = @stub.empty_call(Empty.new)
     assert('empty_unary: invalid response') { resp.is_a?(Empty) }
-    p 'OK: empty_unary'
   end
 
   def large_unary
     perform_large_unary
-    p 'OK: large_unary'
   end
 
   def service_account_creds
@@ -230,7 +228,6 @@
     assert("#{__callee__}: bad oauth scope") do
       @args.oauth_scope.include?(resp.oauth_scope)
     end
-    p "OK: #{__callee__}"
   end
 
   def jwt_token_creds
@@ -238,7 +235,6 @@
     wanted_email = MultiJson.load(json_key)['client_email']
     resp = perform_large_unary(fill_username: true)
     assert("#{__callee__}: bad username") { wanted_email == resp.username }
-    p "OK: #{__callee__}"
   end
 
   def compute_engine_creds
@@ -247,7 +243,6 @@
     assert("#{__callee__}: bad username") do
       @args.default_service_account == resp.username
     end
-    p "OK: #{__callee__}"
   end
 
   def oauth2_auth_token
@@ -259,7 +254,6 @@
     assert("#{__callee__}: bad oauth scope") do
       @args.oauth_scope.include?(resp.oauth_scope)
     end
-    p "OK: #{__callee__}"
   end
 
   def per_rpc_creds
@@ -279,7 +273,6 @@
     assert("#{__callee__}: bad oauth scope") do
       @args.oauth_scope.include?(resp.oauth_scope)
     end
-    p "OK: #{__callee__}"
   end
 
   def client_streaming
@@ -293,7 +286,6 @@
     assert("#{__callee__}: aggregate payload size is incorrect") do
       wanted_aggregate_size == resp.aggregated_payload_size
     end
-    p "OK: #{__callee__}"
   end
 
   def server_streaming
@@ -311,7 +303,6 @@
         :COMPRESSABLE == r.payload.type
       end
     end
-    p "OK: #{__callee__}"
   end
 
   def ping_pong
@@ -319,7 +310,6 @@
     ppp = PingPongPlayer.new(msg_sizes)
     resps = @stub.full_duplex_call(ppp.each_item)
     resps.each { |r| ppp.queue.push(r) }
-    p "OK: #{__callee__}"
   end
 
   def timeout_on_sleeping_server
@@ -332,7 +322,6 @@
     assert("#{__callee__}: status was wrong") do
       e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
     end
-    p "OK: #{__callee__}"
   end
 
   def empty_stream
@@ -346,7 +335,6 @@
     assert("#{__callee__}: too many responses expected 0") do
       count == 0
     end
-    p "OK: #{__callee__}"
   end
 
   def cancel_after_begin
@@ -361,7 +349,6 @@
     fail 'Should have raised GRPC:Cancelled'
   rescue GRPC::Cancelled
     assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
-    p "OK: #{__callee__}"
   end
 
   def cancel_after_first_response
@@ -374,7 +361,6 @@
   rescue GRPC::Cancelled
     assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled }
     op.wait
-    p "OK: #{__callee__}"
   end
 
   def all
@@ -442,7 +428,7 @@
     opts.on('--use_tls USE_TLS', ['false', 'true'],
             'require a secure connection?') do |v|
       args['secure'] = v == 'true'
-    end
+p    end
     opts.on('--use_test_ca USE_TEST_CA', ['false', 'true'],
             'if secure, use the test certificate?') do |v|
       args['use_test_ca'] = v == 'true'
@@ -464,6 +450,9 @@
   opts = parse_args
   stub = create_stub(opts)
   NamedTests.new(stub, opts).method(opts['test_case']).call
+  p "OK: #{opts['test_case']}"
 end
 
-main
+if __FILE__ == $0
+  main
+end
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index 851e815..914c7cc 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -39,7 +39,7 @@
 
 this_dir = File.expand_path(File.dirname(__FILE__))
 lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib')
-pb_dir = File.dirname(File.dirname(this_dir))
+pb_dir = File.dirname(this_dir)
 $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
 $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
 $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
diff --git a/src/ruby/stress/metrics_server.rb b/src/ruby/stress/metrics_server.rb
new file mode 100644
index 0000000..13638c4
--- /dev/null
+++ b/src/ruby/stress/metrics_server.rb
@@ -0,0 +1,83 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
+# OWNER OR 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.
+
+require_relative '../pb/grpc/testing/metrics.rb'
+require_relative '../pb/grpc/testing/metrics_services.rb'
+
+class Gauge
+  def get_name
+    raise NoMethodError.new
+  end
+
+  def get_type
+    raise NoMethodError.new
+  end
+
+  def get_value
+    raise NoMethodError.new
+  end
+end
+
+class MetricsServiceImpl < Grpc::Testing::MetricsService::Service
+  include Grpc::Testing
+  @gauges
+
+  def initialize
+    @gauges = {}
+  end
+
+  def register_gauge(gauge)
+    @gauges[gauge.get_name] = gauge
+  end
+
+  def make_gauge_response(gauge)
+    response = GaugeResponse.new(:name => gauge.get_name)
+    value = gauge.get_value
+    case gauge.get_type
+    when 'long'
+      response.long_value = value
+    when 'double'
+      response.double_value = value
+    when 'string'
+      response.string_value = value
+    end
+    response
+  end
+
+  def get_all_gauges(_empty, _call)
+    @gauges.values.map do |gauge|
+      make_gauge_response gauge
+    end
+  end
+
+  def get_gauge(gauge_req, _call)
+    gauge = @gauges[gauge_req.name]
+    make_gauge_response gauge
+  end
+end
diff --git a/src/ruby/stress/stress_client.rb b/src/ruby/stress/stress_client.rb
new file mode 100755
index 0000000..698f9f1
--- /dev/null
+++ b/src/ruby/stress/stress_client.rb
@@ -0,0 +1,155 @@
+#!/usr/bin/env ruby
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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
+# OWNER OR 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.
+
+require 'optparse'
+require 'thread'
+require_relative '../pb/test/client'
+require_relative './metrics_server'
+require_relative '../lib/grpc'
+
+class QpsGauge < Gauge
+  @query_count
+  @query_mutex
+  @start_time
+
+  def initialize
+    @query_count = 0
+    @query_mutex = Mutex.new
+    @start_time = Time.now
+  end
+
+  def increment_queries
+    @query_mutex.synchronize { @query_count += 1}
+  end
+
+  def get_name
+    'qps'
+  end
+
+  def get_type
+    'long'
+  end
+
+  def get_value
+    (@query_mutex.synchronize { @query_count / (Time.now - @start_time) }).to_i
+  end
+end
+
+def start_metrics_server(port)
+  host = "0.0.0.0:#{port}"
+  server = GRPC::RpcServer.new
+  server.add_http2_port(host, :this_port_is_insecure)
+  service = MetricsServiceImpl.new
+  server.handle(service)
+  server_thread = Thread.new { server.run_till_terminated }
+  [server, service, server_thread]
+end
+
+StressArgs = Struct.new(:server_addresses, :test_cases, :duration,
+                        :channels_per_server, :concurrent_calls, :metrics_port)
+
+def start(stress_args)
+  running = true
+  threads = []
+  qps_gauge = QpsGauge.new
+  metrics_server, metrics_service, metrics_thread =
+    start_metrics_server(stress_args.metrics_port)
+  metrics_service.register_gauge(qps_gauge)
+  stress_args.server_addresses.each do |address|
+    stress_args.channels_per_server.times do
+      client_args = Args.new
+      client_args.host, client_args.port = address.split(':')
+      client_args.secure = false
+      client_args.test_case = ''
+      stub = create_stub(client_args)
+      named_tests = NamedTests.new(stub, client_args)
+      stress_args.concurrent_calls.times do
+        threads << Thread.new do
+          while running
+            named_tests.method(stress_args.test_cases.sample).call
+            qps_gauge.increment_queries
+          end
+        end
+      end
+    end
+  end
+  if stress_args.duration >= 0
+    sleep stress_args.duration
+    running = false
+    metrics_server.stop
+    p "QPS: #{qps_gauge.get_value}"
+    threads.each { |thd| thd.join; }
+  end
+  metrics_thread.join
+end
+
+def parse_stress_args
+  stress_args = StressArgs.new
+  stress_args.server_addresses = ['localhost:8080']
+  stress_args.test_cases = []
+  stress_args.duration = -1
+  stress_args.channels_per_server = 1
+  stress_args.concurrent_calls = 1
+  stress_args.metrics_port = '8081'
+  OptionParser.new do |opts|
+    opts.on('--server_addresses [LIST]', Array) do |addrs|
+      stress_args.server_addresses = addrs
+    end
+    opts.on('--test_cases cases', Array) do |cases|
+      stress_args.test_cases = (cases.map do |item|
+                                  split = item.split(':')
+                                  [split[0]] * split[1].to_i
+                                end).reduce([], :+)
+    end
+    opts.on('--test_duration_secs [INT]', OptionParser::DecimalInteger) do |time|
+      stress_args.duration = time
+    end
+    opts.on('--num_channels_per_server [INT]', OptionParser::DecimalInteger) do |channels|
+      stress_args.channels_per_server = channels
+    end
+    opts.on('--num_stubs_per_channel [INT]', OptionParser::DecimalInteger) do |stubs|
+      stress_args.concurrent_calls = stubs
+    end
+    opts.on('--metrics_port [port]') do |port|
+      stress_args.metrics_port = port
+    end
+  end.parse!
+  stress_args
+end
+
+def main
+  opts = parse_stress_args
+  start(opts)
+end
+
+if __FILE__ == $0
+  main
+end
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index 6f8d1fb..ce775ff 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -26,10 +26,6 @@
     s.files += Dir.glob('include/grpc/**/*')
     s.test_files = Dir.glob('src/ruby/spec/**/*')
     s.bindir = 'src/ruby/bin'
-    ${'%'}w(math noproto).each do |b|
-      s.executables += ["#{b}_client.rb", "#{b}_server.rb"]
-    end
-    s.executables += %w(grpc_ruby_interop_client grpc_ruby_interop_server)
     s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
     s.platform      = Gem::Platform::RUBY
 
diff --git a/templates/package.json.template b/templates/package.json.template
index 5db2706..11718b1 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -21,7 +21,7 @@
       "lib": "src/node/src"
     },
     "scripts": {
-      "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js",
+      "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js --exclude-path=src/node/.jshintignore",
       "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
       "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
       "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
@@ -37,6 +37,7 @@
     "devDependencies": {
       "async": "^1.5.0",
       "google-auth-library": "^0.9.2",
+      "google-protobuf": "^3.0.0-alpha.5",
       "istanbul": "^0.3.21",
       "jsdoc": "^3.3.2",
       "jshint": "^2.5.0",
@@ -74,5 +75,25 @@
       "binding.gyp"
     ],
     "main": "src/node/index.js",
-    "license": "BSD-3-Clause"
+    "license": "BSD-3-Clause",
+    "jshintConfig" : {
+      "bitwise": true,
+      "curly": true,
+      "eqeqeq": true,
+      "esnext": true,
+      "freeze": true,
+      "immed": true,
+      "indent": 2,
+      "latedef": "nofunc",
+      "maxlen": 80,
+      "mocha": true,
+      "newcap": true,
+      "node": true,
+      "noarg": true,
+      "quotmark": "single",
+      "strict": true,
+      "trailing": true,
+      "undef": true,
+      "unused": "vars"
+    }
   }
diff --git a/templates/package.xml.template b/templates/package.xml.template
index 2f498c02..63132da 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -12,7 +12,7 @@
     <email>grpc-packages@google.com</email>
     <active>yes</active>
    </lead>
-   <date>2016-03-01</date>
+   <date>2016-04-19</date>
    <time>16:06:07</time>
    <version>
     <release>${settings.php_version.php()}</release>
@@ -24,7 +24,7 @@
    </stability>
    <license>BSD</license>
    <notes>
-  - Increase unit test code coverage #5225
+  - destroy grpc_byte_buffer after startBatch #6096
    </notes>
    <contents>
     <dir baseinstalldir="/" name="/">
@@ -157,8 +157,8 @@
     </release>
     <release>
      <version>
-      <release>${settings.php_version.php()}</release>
-      <api>${settings.php_version.php()}</api>
+      <release>0.8.1</release>
+      <api>0.8.1</api>
      </version>
      <stability>
       <release>beta</release>
@@ -170,5 +170,20 @@
   - Increase unit test code coverage #5225
      </notes>
     </release>
+    <release>
+     <version>
+      <release>${settings.php_version.php()}</release>
+      <api>${settings.php_version.php()}</api>
+     </version>
+     <stability>
+      <release>beta</release>
+      <api>beta</api>
+     </stability>
+     <date>2016-04-19</date>
+     <license>BSD</license>
+     <notes>
+  - destroy grpc_byte_buffer after startBatch #6096
+     </notes>
+    </release>
    </changelog>
   </package>
diff --git a/templates/src/csharp/Grpc.Core/VersionInfo.cs.template b/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
index 3ca111e..96cf2ee 100644
--- a/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
+++ b/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
@@ -37,13 +37,20 @@
   {
       /// <summary>
       /// Provides info about current version of gRPC.
+      /// See https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/
+      /// for rationale about assembly versioning.
       /// </summary>
       public static class VersionInfo
       {
           /// <summary>
-          /// Current version of gRPC C# assemblies
+          /// Current <c>AssemblyVersion</c> attribute of gRPC C# assemblies
           /// </summary>
-          public const string CurrentAssemblyVersion = "${settings.version.major}.${settings.version.minor}.${settings.version.patch}.0";
+          public const string CurrentAssemblyVersion = "1.0.0.0";
+
+          /// <summary>
+          /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
+          /// </summary>
+          public const string CurrentAssemblyFileVersion = "${settings.version.major}.${settings.version.minor}.${settings.version.patch}.0";
 
           /// <summary>
           /// Current version of gRPC C#
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 28b91f8..18d4c10 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -270,13 +270,13 @@
     self.safename = str(self)
 
   def client_cmd(self, args):
-    return ['ruby', 'src/ruby/bin/interop/interop_client.rb'] + args
+    return ['ruby', 'src/ruby/pb/test/client.rb'] + args
 
   def cloud_to_prod_env(self):
     return {}
 
   def server_cmd(self, args):
-    return ['ruby', 'src/ruby/bin/interop/interop_server.rb', '--use_tls=true'] + args
+    return ['ruby', 'src/ruby/pb/test/server.rb', '--use_tls=true'] + args
 
   def global_env(self):
     return {}
@@ -314,7 +314,8 @@
     ]
 
   def global_env(self):
-    return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT)}
+    return {'LD_LIBRARY_PATH': '{}/libs/opt'.format(DOCKER_WORKDIR_ROOT),
+            'PYTHONPATH': '{}/src/python/gens'.format(DOCKER_WORKDIR_ROOT)}
 
   def unimplemented_test_cases(self):
     return _SKIP_ADVANCED + _SKIP_COMPRESSION + ['jwt_token_creds',
@@ -590,8 +591,8 @@
                       False),
     'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
                          True),
-    'gateway_v4': ('grpc-test4.sandbox.googleapis.com', 
-                   'grpc-test4.sandbox.googleapis.com', True), 
+    'gateway_v4': ('grpc-test4.sandbox.googleapis.com',
+                   'grpc-test4.sandbox.googleapis.com', True),
     'cloud_gateway_v4': ('216.239.32.255', 'grpc-test4.sandbox.googleapis.com',
                          True),
 }
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 9dff686..4b98985 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -371,6 +371,7 @@
       tests_json = json.load(tests_json_file)
     environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
     environment['PYVER'] = '2.7'
+    environment['PYTHONPATH'] = os.path.abspath('src/python/gens')
     if self.config.build_config != 'gcov':
       return [self.config.job_spec(
           ['tools/run_tests/run_python.sh'],
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index bb51ecd..e94387c 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -2176,6 +2176,19 @@
     ], 
     "headers": [], 
     "language": "c++", 
+    "name": "grpc_node_plugin", 
+    "src": [
+      "src/compiler/node_plugin.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "grpc_plugin_support"
+    ], 
+    "headers": [], 
+    "language": "c++", 
     "name": "grpc_objective_c_plugin", 
     "src": [
       "src/compiler/objective_c_plugin.cc"
@@ -4363,6 +4376,8 @@
       "src/compiler/csharp_generator.h", 
       "src/compiler/csharp_generator_helpers.h", 
       "src/compiler/generator_helpers.h", 
+      "src/compiler/node_generator.h", 
+      "src/compiler/node_generator_helpers.h", 
       "src/compiler/objective_c_generator.h", 
       "src/compiler/objective_c_generator_helpers.h", 
       "src/compiler/python_generator.h", 
@@ -4382,6 +4397,9 @@
       "src/compiler/csharp_generator.h", 
       "src/compiler/csharp_generator_helpers.h", 
       "src/compiler/generator_helpers.h", 
+      "src/compiler/node_generator.cc", 
+      "src/compiler/node_generator.h", 
+      "src/compiler/node_generator_helpers.h", 
       "src/compiler/objective_c_generator.cc", 
       "src/compiler/objective_c_generator.h", 
       "src/compiler/objective_c_generator_helpers.h", 
diff --git a/vsprojects/grpc_protoc_plugins.sln b/vsprojects/grpc_protoc_plugins.sln
index ef1cbb8..ace295d 100644
--- a/vsprojects/grpc_protoc_plugins.sln
+++ b/vsprojects/grpc_protoc_plugins.sln
@@ -24,6 +24,14 @@
 		{B6E81D84-2ACB-41B8-8781-493A944C7817} = {B6E81D84-2ACB-41B8-8781-493A944C7817}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_node_plugin", "vcxproj\.\grpc_node_plugin\grpc_node_plugin.vcxproj", "{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{B6E81D84-2ACB-41B8-8781-493A944C7817} = {B6E81D84-2ACB-41B8-8781-493A944C7817}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_objective_c_plugin", "vcxproj\.\grpc_objective_c_plugin\grpc_objective_c_plugin.vcxproj", "{19564640-CEE6-4921-ABA5-676ED79A36F6}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -80,6 +88,14 @@
 		{3C813052-A49A-4662-B90A-1ADBEC7EE453}.Debug|x64.Build.0 = Debug|x64
 		{3C813052-A49A-4662-B90A-1ADBEC7EE453}.Release|Win32.Build.0 = Release|Win32
 		{3C813052-A49A-4662-B90A-1ADBEC7EE453}.Release|x64.Build.0 = Release|x64
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Debug|Win32.ActiveCfg = Debug|Win32
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Debug|x64.ActiveCfg = Debug|x64
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Release|Win32.ActiveCfg = Release|Win32
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Release|x64.ActiveCfg = Release|x64
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Debug|Win32.Build.0 = Debug|Win32
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Debug|x64.Build.0 = Debug|x64
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Release|Win32.Build.0 = Release|Win32
+		{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}.Release|x64.Build.0 = Release|x64
 		{19564640-CEE6-4921-ABA5-676ED79A36F6}.Debug|Win32.ActiveCfg = Debug|Win32
 		{19564640-CEE6-4921-ABA5-676ED79A36F6}.Debug|x64.ActiveCfg = Debug|x64
 		{19564640-CEE6-4921-ABA5-676ED79A36F6}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/grpc_node_plugin/grpc_node_plugin.vcxproj b/vsprojects/vcxproj/grpc_node_plugin/grpc_node_plugin.vcxproj
new file mode 100644
index 0000000..faf93fd
--- /dev/null
+++ b/vsprojects/vcxproj/grpc_node_plugin/grpc_node_plugin.vcxproj
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{57ABD9A2-CE8E-CCA7-5171-35C4534F3595}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protoc.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>grpc_node_plugin</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>grpc_node_plugin</TargetName>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\compiler\node_plugin.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_plugin_support\grpc_plugin_support.vcxproj">
+      <Project>{B6E81D84-2ACB-41B8-8781-493A944C7817}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc_node_plugin/grpc_node_plugin.vcxproj.filters b/vsprojects/vcxproj/grpc_node_plugin/grpc_node_plugin.vcxproj.filters
new file mode 100644
index 0000000..28b197f
--- /dev/null
+++ b/vsprojects/vcxproj/grpc_node_plugin/grpc_node_plugin.vcxproj.filters
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\compiler\node_plugin.cc">
+      <Filter>src\compiler</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{089d5d6b-d438-dc98-b30f-bd608e3bbb78}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\compiler">
+      <UniqueIdentifier>{1cc34440-c001-7578-c4d3-78f5d98fb602}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
index 4c80226..a81d317 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
@@ -160,6 +160,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\compiler\csharp_generator.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\csharp_generator_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\generator_helpers.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\node_generator.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\node_generator_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\objective_c_generator.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\objective_c_generator_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\python_generator.h" />
@@ -173,6 +175,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\compiler\csharp_generator.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\compiler\node_generator.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\compiler\objective_c_generator.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\compiler\python_generator.cc">
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
index fc125d9..b3d2dc2 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
@@ -7,6 +7,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\compiler\csharp_generator.cc">
       <Filter>src\compiler</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\compiler\node_generator.cc">
+      <Filter>src\compiler</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\compiler\objective_c_generator.cc">
       <Filter>src\compiler</Filter>
     </ClCompile>
@@ -50,6 +53,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\compiler\generator_helpers.h">
       <Filter>src\compiler</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\node_generator.h">
+      <Filter>src\compiler</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\compiler\node_generator_helpers.h">
+      <Filter>src\compiler</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\compiler\objective_c_generator.h">
       <Filter>src\compiler</Filter>
     </ClInclude>