Integrated internal changes from Google
diff --git a/js/binary/constants.js b/js/binary/constants.js
index 75a8a52..21c5889 100644
--- a/js/binary/constants.js
+++ b/js/binary/constants.js
@@ -60,14 +60,25 @@
 
 
 /**
- * Base interface class for all const messages. Does __not__ define any
- * methods, as doing so on a widely-used interface defeats dead-code
- * elimination.
+ * Base interface class for all const messages.
  * @interface
  */
 jspb.ConstBinaryMessage = function() {};
 
+/**
+ * Generate a debug string for this proto that is in proto2 text format.
+ * @return {string} The debug string.
+ */
+jspb.ConstBinaryMessage.prototype.toDebugString;
 
+/**
+ * Helper to generate a debug string for this proto at some indent level. The
+ * first line is not indented.
+ * @param {number} indentLevel The number of spaces by which to indent lines.
+ * @return {string} The debug string.
+ * @protected
+ */
+jspb.ConstBinaryMessage.prototype.toDebugStringInternal;
 
 /**
  * Base interface class for all messages. Does __not__ define any methods, as
@@ -97,6 +108,7 @@
  * A repeated field in jspb is an array of scalars, blobs, or messages.
  * @typedef {!Array<jspb.ScalarFieldType>|
              !Array<!Uint8Array>|
+             !Array<!jspb.ConstBinaryMessage>|
              !Array<!jspb.BinaryMessage>}
  */
 jspb.RepeatedFieldType;
@@ -108,6 +120,7 @@
  * @typedef {jspb.ScalarFieldType|
              jspb.RepeatedFieldType|
              !Uint8Array|
+             !jspb.ConstBinaryMessage|
              !jspb.BinaryMessage|
              !jsproto.BinaryExtension}
  */
diff --git a/js/binary/decoder.js b/js/binary/decoder.js
index d0c0bc1..e33bf1b 100644
--- a/js/binary/decoder.js
+++ b/js/binary/decoder.js
@@ -986,7 +986,7 @@
       codeUnits.push(high, low);
     }
 
-    // Avoid exceeding the maximum stack size when calling {@code apply}.
+    // Avoid exceeding the maximum stack size when calling `apply`.
     if (codeUnits.length >= 8192) {
       result += String.fromCharCode.apply(null, codeUnits);
       codeUnits.length = 0;
diff --git a/js/binary/writer.js b/js/binary/writer.js
index 8a01805..287d29c 100644
--- a/js/binary/writer.js
+++ b/js/binary/writer.js
@@ -236,10 +236,12 @@
 
 /**
  * Converts the encoded data into a base64-encoded string.
+ * @param {boolean=} opt_webSafe True indicates we should use a websafe
+ *     alphabet, which does not require escaping for use in URLs.
  * @return {string}
  */
-jspb.BinaryWriter.prototype.getResultBase64String = function() {
-  return goog.crypt.base64.encodeByteArray(this.getResultBuffer());
+jspb.BinaryWriter.prototype.getResultBase64String = function(opt_webSafe) {
+  return goog.crypt.base64.encodeByteArray(this.getResultBuffer(), opt_webSafe);
 };
 
 
diff --git a/js/binary/writer_test.js b/js/binary/writer_test.js
index 118eecf..8a9a1bb 100644
--- a/js/binary/writer_test.js
+++ b/js/binary/writer_test.js
@@ -118,4 +118,16 @@
     var buffer = writer.getResultBuffer();
     assertEquals(expected, goog.crypt.byteArrayToHex(buffer));
   });
+
+
+  /**
+   * Tests websafe encodings for base64 strings.
+   */
+  it('testWebSafeOption', function() {
+    var writer = new jspb.BinaryWriter();
+    writer.writeBytes(1, new Uint8Array([127]));
+    assertEquals('CgF/', writer.getResultBase64String());
+    assertEquals('CgF/', writer.getResultBase64String(false));
+    assertEquals('CgF_', writer.getResultBase64String(true));
+  });
 });