Version 0.6.21.1

svn merge -c 26577 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 26578 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 26579 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 26582 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 26585 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@26594 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/bin/filter.cc b/runtime/bin/filter.cc
index 43b08e7..0babea9 100644
--- a/runtime/bin/filter.cc
+++ b/runtime/bin/filter.cc
@@ -82,19 +82,22 @@
   Dart_Handle filter_obj = Dart_GetNativeArgument(args, 0);
   Filter* filter = GetFilter(filter_obj);
   Dart_Handle data_obj = Dart_GetNativeArgument(args, 1);
+  intptr_t start = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
+  intptr_t end = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
+  intptr_t chunk_length = end - start;
   intptr_t length;
   Dart_TypedData_Type type;
   uint8_t* buffer = NULL;
   Dart_Handle result = Dart_TypedDataAcquireData(
       data_obj, &type, reinterpret_cast<void**>(&buffer), &length);
   if (!Dart_IsError(result)) {
-    uint8_t* zlib_buffer = new uint8_t[length];
+    uint8_t* zlib_buffer = new uint8_t[chunk_length];
     if (zlib_buffer == NULL) {
       Dart_TypedDataReleaseData(data_obj);
       Dart_ThrowException(DartUtils::NewInternalError(
           "Failed to allocate buffer for zlib"));
     }
-    memmove(zlib_buffer, buffer, length);
+    memmove(zlib_buffer, buffer + start, chunk_length);
     Dart_TypedDataReleaseData(data_obj);
     buffer = zlib_buffer;
   } else {
@@ -102,15 +105,16 @@
       Dart_ThrowException(DartUtils::NewInternalError(
           "Failed to get list length"));
     }
-    buffer = new uint8_t[length];
-    if (Dart_IsError(Dart_ListGetAsBytes(data_obj, 0, buffer, length))) {
+    buffer = new uint8_t[chunk_length];
+    if (Dart_IsError(Dart_ListGetAsBytes(
+            data_obj, start, buffer, chunk_length))) {
       delete[] buffer;
       Dart_ThrowException(DartUtils::NewInternalError(
           "Failed to get list bytes"));
     }
   }
   // Process will take ownership of buffer, if successful.
-  if (!filter->Process(buffer, length)) {
+  if (!filter->Process(buffer, chunk_length)) {
     delete[] buffer;
     EndFilter(filter_obj, filter);
     Dart_ThrowException(DartUtils::NewInternalError(
diff --git a/runtime/bin/filter_patch.dart b/runtime/bin/filter_patch.dart
index b549aaf..1dc727d 100644
--- a/runtime/bin/filter_patch.dart
+++ b/runtime/bin/filter_patch.dart
@@ -4,7 +4,7 @@
 
 
 class _FilterImpl extends NativeFieldWrapperClass1 implements _Filter {
-  void process(List<int> data) native "Filter_Process";
+  void process(List<int> data, int start, int end) native "Filter_Process";
 
   List<int> processed({bool flush: true, bool end: false})
       native "Filter_Processed";
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index eb5b444..28b5b6d 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -25,7 +25,7 @@
   V(Filter_CreateZLibDeflate, 3)                                               \
   V(Filter_CreateZLibInflate, 1)                                               \
   V(Filter_End, 1)                                                             \
-  V(Filter_Process, 2)                                                         \
+  V(Filter_Process, 4)                                                         \
   V(Filter_Processed, 3)                                                       \
   V(InternetAddress_Fixed, 1)                                                  \
   V(Platform_NumberOfProcessors, 0)                                            \
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 36e3deb..9815cea 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -255,7 +255,7 @@
       current_class_(Class::Handle(isolate_)),
       library_(Library::Handle(isolate_, library.raw())),
       try_blocks_list_(NULL),
-      last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
+      last_used_try_index_(0),
       unregister_pending_function_(false) {
   ASSERT(tokens_iterator_.IsValid());
   ASSERT(!library.IsNull());
@@ -285,7 +285,7 @@
           isolate_,
           parsed_function->function().origin()).library())),
       try_blocks_list_(NULL),
-      last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
+      last_used_try_index_(0),
       unregister_pending_function_(false) {
   ASSERT(tokens_iterator_.IsValid());
   ASSERT(!current_function().IsNull());
@@ -2646,11 +2646,16 @@
       Function::Handle(innermost_function().raw());
   innermost_function_ = func.raw();
 
+  // Save current try index. Try index starts at zero for each function.
+  intptr_t saved_try_index = last_used_try_index_;
+  last_used_try_index_ = 0;
+
   // TODO(12455) : Need better validation mechanism.
 
   if (func.IsConstructor()) {
     SequenceNode* statements = ParseConstructor(func, default_parameter_values);
     innermost_function_ = saved_innermost_function.raw();
+    last_used_try_index_ = saved_try_index;
     return statements;
   }
 
@@ -2760,6 +2765,7 @@
   SequenceNode* body = CloseBlock();
   current_block_->statements->Add(body);
   innermost_function_ = saved_innermost_function.raw();
+  last_used_try_index_ = saved_try_index;
   return CloseBlock();
 }
 
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index b2fbf97..e7161a5 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -693,7 +693,7 @@
   TryBlocks* try_blocks_list_;
 
   // Each try in this function gets its own try index.
-  intptr_t AllocateTryIndex() { return ++last_used_try_index_; }
+  intptr_t AllocateTryIndex() { return last_used_try_index_++; }
   intptr_t last_used_try_index_;
 
   bool unregister_pending_function_;
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index 5d7f79a..96a6d40 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -21,22 +21,75 @@
  * It is a compile-time error for a class to attempt to extend or implement int.
  */
 abstract class int extends num {
-  /** The bit-wise and operator. */
+  /**
+   * Bit-wise and operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with only the bits set that are set in
+   * both `this` and [other]
+   *
+   * Of both operands are negative, the result is negative, otherwise
+   * the result is non-negative.
+   */
   int operator &(int other);
 
-  /** The bit-wise or operator. */
+  /**
+   * Bit-wise or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in either
+   * of `this` and [other]
+   *
+   * If both operands are non-negative, the result is non-negative,
+   * otherwise the result us negative.
+   */
   int operator |(int other);
 
-  /** The bit-wise xor operator. */
+  /**
+   * Bit-wise exclusive-or operator.
+   *
+   * Treating both `this` and [other] as sufficiently large two's component
+   * integers, the result is a number with the bits set that are set in one,
+   * but not both, of `this` and [other]
+   *
+   * If the operands have the same sign, the result is non-negative,
+   * otherwise the result is negative.
+   */
   int operator ^(int other);
 
-  /** The bit-wise negate operator. */
+  /**
+   * The bit-wise negate operator.
+   *
+   * Treating `this` as a sufficiently large two's component integer,
+   * the result is a number with the opposite bits set.
+   *
+   * This maps any integer `x` to `-x - 1`.
+   */
   int operator ~();
 
-  /** The left shift operator. */
+  /**
+   * Shift the bits of this integer to the left by [shiftAmount].
+   *
+   * Shifting to the left makes the number larger, effectively multiplying
+   * the number by `pow(2, shiftIndex)`.
+   *
+   * There is no limit on the size of the result. It may be relevant to
+   * limit intermediate values by using the "and" operator with a suitable
+   * mask.
+   *
+   * It is an error of [shiftAmount] is negative.
+   */
   int operator <<(int shiftAmount);
 
-  /** The right shift operator. */
+  /**
+   * Shift the bits of this integer to the right by [shiftAmount].
+   *
+   * Shifting to the right makes the number smaller and drops the least
+   * significant bits, effectively doing an integer division by
+   *`pow(2, shiftIndex)`.
+   *
+   * It is an error of [shiftAmount] is negative.
+   */
   int operator >>(int shiftAmount);
 
   /** Returns true if and only if this integer is even. */
@@ -45,10 +98,19 @@
   /** Returns true if and only if this integer is odd. */
   bool get isOdd;
 
-  /** Negate operator. Negating an integer produces an integer. */
+  /**
+   * Return the negative value of this integer.
+   *
+   * The result of negating an integer always has the opposite sign, except
+   * for zero, which is its own negation.
+   */
   int operator -();
 
-  /** Returns the absolute value of this integer. */
+  /**
+   * Returns the absolute value of this integer.
+   *
+   * For any integer `x`, the result is the same as `x < 0 ? -x : x`.
+   */
   int abs();
 
   /** Returns `this`. */
@@ -57,10 +119,10 @@
   /** Returns `this`. */
   int floor();
 
-  /** Returns [this]. */
+  /** Returns `this`. */
   int ceil();
 
-  /** Returns [this]. */
+  /** Returns `this`. */
   int truncate();
 
   /** Returns `this.toDouble()`. */
@@ -76,10 +138,11 @@
   double truncateToDouble();
 
   /**
-   * Returns a representation of this [int] value.
+   * Returns a String-representation of this integer.
    *
-   * It should always be the case that if [:i:] is an [int] value,
-   * then [:i == int.parse(i.toString()):].
+   * The returned string is parsable by [parse].
+   * For any `int` [:i:], it is guaranteed that
+   * [:i == int.parse(i.toString()):].
    */
   String toString();
 
diff --git a/sdk/lib/io/data_transformer.dart b/sdk/lib/io/data_transformer.dart
index c7c53ad..fb3fbe4 100644
--- a/sdk/lib/io/data_transformer.dart
+++ b/sdk/lib/io/data_transformer.dart
@@ -4,6 +4,261 @@
 
 part of dart.io;
 
+
+/**
+ * An instance of the default implementation of the [ZLibCodec].
+ */
+const ZLIB = const ZLibCodec();
+
+
+/**
+ * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib
+ * compressed bytes to raw bytes.
+ */
+class ZLibCodec extends Codec<List<int>, List<int>> {
+  /**
+   * The compression level of the [ZLibCodec].
+   */
+  final int level;
+
+  /**
+   * Get a [Converter] for encoding to `ZLib` compressed data.
+   */
+  Converter<List<int>, List<int>> get encoder =>
+      new ZLibEncoder(gzip: false, level: level);
+
+  /**
+   * Get a [Converter] for decoding `ZLib` compressed data.
+   */
+  Converter<List<int>, List<int>> get decoder => const ZLibDecoder();
+
+  /**
+   * The compression-[level] can be set in the range of `1..10`, with `6` being
+   * the default compression level. Levels above 6 will have higher compression
+   * rates at the cost of more CPU and memory usage. Levels below 6 will use
+   * less CPU and memory, but at the cost of lower compression rates.
+   */
+  const ZLibCodec({this.level: 6});
+}
+
+
+/**
+ * An instance of the default implementation of the [GZipCodec].
+ */
+const GZIP = const GZipCodec();
+
+
+/**
+ * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip
+ * compressed bytes to raw bytes.
+ *
+ * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec]
+ * wraps the `ZLib` compressed bytes in `GZip` frames.
+ */
+class GZipCodec extends Codec<List<int>, List<int>> {
+  /**
+   * The compression level of the [ZLibCodec].
+   */
+  final int level;
+
+  /**
+   * Get a [Converter] for encoding to `GZip` compressed data.
+   */
+  Converter<List<int>, List<int>> get encoder =>
+      new ZLibEncoder(gzip: true, level: level);
+
+  /**
+   * Get a [Converter] for decoding `GZip` compressed data.
+   */
+  Converter<List<int>, List<int>> get decoder => const ZLibDecoder();
+
+  /**
+   * The compression-[level] can be set in the range of `1..10`, with `6` being
+   * the default compression level. Levels above 6 will have higher compression
+   * rates at the cost of more CPU and memory usage. Levels below 6 will use
+   * less CPU and memory, but at the cost of lower compression rates.
+   */
+  const GZipCodec({this.level: 6});
+}
+
+
+/**
+ * The [ZLibEncoder] is the encoder used by [ZLibCodec] and [GZipCodec] to
+ * compress data.
+ */
+class ZLibEncoder extends Converter<List<int>, List<int>> {
+  /**
+   * If [gzip] is true, `GZip` frames will be added to the compressed data.
+   */
+  final bool gzip;
+
+  /**
+   * The compression level used by the encoder.
+   */
+  final int level;
+
+  /**
+   * Create a new [ZLibEncoder] converter. If the [gzip] flag is set, the
+   * encoder will wrap the encoded ZLib data in GZip frames.
+   */
+  const ZLibEncoder({this.gzip: false, this.level: 6});
+
+
+  /**
+   * Convert a list of bytes using the options given to the [ZLibEncoder]
+   * constructor.
+   */
+  List<int> convert(List<int> bytes) {
+    _BufferSink sink = new _BufferSink();
+    startChunkedConversion(sink)
+      ..add(bytes)
+      ..close();
+    return sink.builder.takeBytes();
+  }
+
+  /**
+   * Start a chunked conversion using the options given to the [ZLibEncoder]
+   * constructor. While it accepts any [ChunkedConversionSink] taking
+   * [List<int>]'s, the optimal sink to be passed as [sink] is a
+   * [ByteConversionSink].
+   */
+  ByteConversionSink startChunkedConversion(
+      ChunkedConversionSink<List<int>> sink) {
+    if (sink is! ByteConversionSink) {
+      sink = new ByteConversionSink.from(sink);
+    }
+    return new _ZLibEncoderSink(sink, gzip, level);
+  }
+}
+
+
+/**
+ * The [ZLibDecoder] is the decoder used by [ZLibCodec] and [GZipCodec] to
+ * decompress data.
+ */
+class ZLibDecoder extends Converter<List<int>, List<int>> {
+
+  /**
+   * Create a new [ZLibEncoder] converter.
+   */
+  const ZLibDecoder();
+
+  /**
+   * Convert a list of bytes using the options given to the [ZLibDecoder]
+   * constructor.
+   */
+  List<int> convert(List<int> bytes) {
+    _BufferSink sink = new _BufferSink();
+    startChunkedConversion(sink)
+      ..add(bytes)
+      ..close();
+    return sink.builder.takeBytes();
+  }
+
+  /**
+   * Start a chunked conversion. While it accepts any [ChunkedConversionSink]
+   * taking [List<int>]'s, the optimal sink to be passed as [sink] is a
+   * [ByteConversionSink].
+   */
+  ByteConversionSink startChunkedConversion(
+      ChunkedConversionSink<List<int>> sink) {
+    if (sink is! ByteConversionSink) {
+      sink = new ByteConversionSink.from(sink);
+    }
+    return new _ZLibDecoderSink(sink);
+  }
+}
+
+
+class _BufferSink extends ByteConversionSink {
+  final BytesBuilder builder = new BytesBuilder();
+
+  void add(List<int> chunk) {
+    builder.add(chunk);
+  }
+
+  void addSlice(List<int> chunk, int start, int end, bool isLast) {
+    if (chunk is Uint8List) {
+      Uint8List list = chunk;
+      builder.add(new Uint8List.view(list.buffer, start, end - start));
+    } else {
+      builder.add(chunk.sublist(start, end));
+    }
+  }
+
+  void close() {}
+}
+
+
+class _ZLibEncoderSink extends _FilterSink {
+  _ZLibEncoderSink(ByteConversionSink sink, bool gzip, int level)
+      : super(sink, _Filter.newZLibDeflateFilter(gzip, level));
+}
+
+
+class _ZLibDecoderSink extends _FilterSink {
+  _ZLibDecoderSink(ByteConversionSink sink)
+      : super(sink, _Filter.newZLibInflateFilter());
+}
+
+
+class _FilterSink extends ByteConversionSink {
+  final _Filter _filter;
+  final ByteConversionSink _sink;
+  bool _closed = false;
+  bool _empty = true;
+
+  _FilterSink(ByteConversionSink this._sink, _Filter this._filter);
+
+  void add(List<int> data) {
+    addSlice(data, 0, data.length, false);
+  }
+
+  void addSlice(List<int> data, int start, int end, bool isLast) {
+    if (_closed) return;
+    if (start < 0 || start > data.length) {
+      throw new ArgumentError("Invalid start position");
+    }
+    if (end < 0 || end > data.length || end < start) {
+      throw new ArgumentError("Invalid end position");
+    }
+    try {
+      _empty = false;
+      _filter.process(data, start, end);
+      var out;
+      while ((out = _filter.processed(flush: false)) != null) {
+        _sink.add(out);
+      }
+    } catch (e) {
+      _closed = true;
+      throw e;
+    }
+
+    if (isLast) close();
+  }
+
+  void close() {
+    if (_closed) return;
+    // Be sure to send process an empty chunk of data. Without this, the empty
+    // message would not have a GZip frame (if compressed with GZip).
+    if (_empty) _filter.process(const [], 0, 0);
+    try {
+      var out;
+      while ((out = _filter.processed(end: true)) != null) {
+        _sink.add(out);
+      }
+    } catch (e) {
+      _closed = true;
+      throw e;
+    }
+    if (!_closed) _filter.end();
+    _closed = true;
+    _sink.close();
+  }
+}
+
+
+
 /**
  * Private helper-class to handle native filters.
  */
@@ -12,7 +267,7 @@
    * Call to process a chunk of data. A call to [process] should only be made
    * when [processed] returns [null].
    */
-  void process(List<int> data);
+  void process(List<int> data, int start, int end);
 
   /**
    * Get a chunk of processed data. When there are no more data available,
@@ -34,65 +289,3 @@
   external static _Filter newZLibDeflateFilter(bool gzip, int level);
   external static _Filter newZLibInflateFilter();
 }
-
-
-class _FilterTransformer extends StreamEventTransformer<List<int>, List<int>> {
-  final _Filter _filter;
-  bool _closed = false;
-  bool _empty = true;
-
-  _FilterTransformer(_Filter this._filter);
-
-  void handleData(List<int> data, EventSink<List<int>> sink) {
-    if (_closed) return;
-    try {
-      _empty = false;
-      _filter.process(data);
-      var out;
-      while ((out = _filter.processed(flush: false)) != null) {
-        sink.add(out);
-      }
-    } catch (e, s) {
-      _closed = true;
-      // TODO(floitsch): we are losing the stack trace.
-      sink.addError(e);
-      sink.close();
-    }
-  }
-
-  void handleDone(EventSink<List<int>> sink) {
-    if (_closed) return;
-    if (_empty) _filter.process(const []);
-    try {
-      var out;
-      while ((out = _filter.processed(end: true)) != null) {
-        sink.add(out);
-      }
-    } catch (e, s) {
-      // TODO(floitsch): we are losing the stack trace.
-      sink.addError(e);
-      _closed = true;
-    }
-    if (!_closed) _filter.end();
-    _closed = true;
-    sink.close();
-  }
-}
-
-
-/**
- * ZLibDeflater class used to deflate a stream of bytes, using zlib.
- */
-class ZLibDeflater extends _FilterTransformer {
-  ZLibDeflater({bool gzip: true, int level: 6})
-      : super(_Filter.newZLibDeflateFilter(gzip, level));
-}
-
-
-/**
- * ZLibInflater class used to inflate a stream of bytes, using zlib.
- */
-class ZLibInflater extends _FilterTransformer {
-  ZLibInflater() : super(_Filter.newZLibInflateFilter());
-}
-
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 7eaf153..f7b9041 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -243,7 +243,7 @@
                                         bool cancelOnError}) {
     var stream = _incoming;
     if (headers.value(HttpHeaders.CONTENT_ENCODING) == "gzip") {
-      stream = stream.transform(new ZLibInflater());
+      stream = stream.transform(GZIP.decoder);
     }
     return stream.listen(onData,
                          onError: onError,
@@ -516,7 +516,7 @@
           stream = stream.transform(new _BufferTransformer());
           if (headers.chunkedTransferEncoding) {
             if (_asGZip) {
-              stream = stream.transform(new ZLibDeflater(gzip: true, level: 6));
+              stream = stream.transform(GZIP.encoder);
             }
             stream = stream.transform(new _ChunkedTransformer());
           } else if (contentLength >= 0) {
diff --git a/tests/language/regress_12615_test.dart b/tests/language/regress_12615_test.dart
new file mode 100644
index 0000000..52b422e
--- /dev/null
+++ b/tests/language/regress_12615_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that try-catch works properly in the VM.
+
+main() {
+  void test() {
+    f() {
+     try {} catch (e) {}
+    }
+    try {} catch (e) {}
+  }
+  test();
+}
+
diff --git a/tests/standalone/io/regress_10026_test.dart b/tests/standalone/io/regress_10026_test.dart
index 444c145..6c386c7 100644
--- a/tests/standalone/io/regress_10026_test.dart
+++ b/tests/standalone/io/regress_10026_test.dart
@@ -12,7 +12,7 @@
     var port = new ReceivePort();
     var controller = new StreamController(sync: true);
     controller.stream
-        .transform(new ZLibInflater())
+        .transform(ZLIB.decoder)
         .transform(new StringDecoder())
         .fold(new StringBuffer(), (buffer, s) {
           buffer.write(s);
diff --git a/tests/standalone/io/zlib_test.dart b/tests/standalone/io/zlib_test.dart
index d1214ae..a7bf2f7 100644
--- a/tests/standalone/io/zlib_test.dart
+++ b/tests/standalone/io/zlib_test.dart
@@ -12,7 +12,7 @@
     var port = new ReceivePort();
     var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
     var controller = new StreamController(sync: true);
-    controller.stream.transform(new ZLibDeflater(gzip: false, level: level))
+    controller.stream.transform(new ZLibEncoder(gzip: false, level: level))
         .fold([], (buffer, data) {
           buffer.addAll(data);
           return buffer;
@@ -32,7 +32,7 @@
 void testZLibDeflateEmpty() {
   var port = new ReceivePort();
   var controller = new StreamController(sync: true);
-  controller.stream.transform(new ZLibDeflater(gzip: false, level: 6))
+  controller.stream.transform(new ZLibEncoder(gzip: false, level: 6))
       .fold([], (buffer, data) {
         buffer.addAll(data);
         return buffer;
@@ -49,7 +49,7 @@
   var port = new ReceivePort();
   var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
   var controller = new StreamController(sync: true);
-  controller.stream.transform(new ZLibDeflater())
+  controller.stream.transform(new ZLibEncoder(gzip: true))
       .fold([], (buffer, data) {
         buffer.addAll(data);
         return buffer;
@@ -70,7 +70,7 @@
   test2(gzip, level) {
     var port = new ReceivePort();
     try {
-      new ZLibDeflater(gzip: gzip, level: level);
+      new ZLibEncoder(gzip: gzip, level: level).startChunkedConversion(null);
     } catch (e) {
       port.close();
     }
@@ -94,8 +94,8 @@
     var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
     var controller = new StreamController(sync: true);
     controller.stream
-      .transform(new ZLibDeflater(gzip: gzip, level: level))
-      .transform(new ZLibInflater())
+      .transform(new ZLibEncoder(gzip: gzip, level: level))
+      .transform(new ZLibDecoder())
         .fold([], (buffer, data) {
           buffer.addAll(data);
           return buffer;
@@ -116,10 +116,27 @@
   }
 }
 
+void testZLibInflateSync() {
+  test2(bool gzip, int level) {
+    var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    var encoded = new ZLibEncoder(gzip: gzip, level: level).convert(data);
+    var decoded = new ZLibDecoder().convert(encoded);
+    Expect.listEquals(data, decoded);
+  }
+  void test(int level) {
+    test2(false, level);
+    test2(true, level);
+  }
+  for (int i = -1; i < 10; i++) {
+    test(i);
+  }
+}
+
 void main() {
   testZLibDeflate();
   testZLibDeflateEmpty();
   testZLibDeflateGZip();
   testZLibDeflateInvalidLevel();
   testZLibInflate();
+  testZLibInflateSync();
 }
diff --git a/tools/VERSION b/tools/VERSION
index 2a8dc7c..20a3e78 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 6
 BUILD 21
-PATCH 0
+PATCH 1