Added full js & js_util packages

R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org//2119523002 .
diff --git a/packages/js/AUTHORS b/packages/js/AUTHORS
new file mode 100644
index 0000000..d773d3a
--- /dev/null
+++ b/packages/js/AUTHORS
@@ -0,0 +1,8 @@
+# Below is a list of people and organizations that have contributed
+# to the Dart project. Names should be added to the list like so:
+#
+#   Name/Organization <email address>
+
+Google Inc.
+
+Alexandre Ardhuin <alexandre.ardhuin@gmail.com>
diff --git a/packages/js/CHANGELOG.md b/packages/js/CHANGELOG.md
new file mode 100644
index 0000000..4ef2ebc
--- /dev/null
+++ b/packages/js/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.6.0
+
+ * Version 0.6.0 is a complete rewrite of `package:js`.
diff --git a/packages/js/LICENSE b/packages/js/LICENSE
new file mode 100644
index 0000000..abbb072
--- /dev/null
+++ b/packages/js/LICENSE
@@ -0,0 +1,24 @@
+Copyright 2012, the Dart project authors. 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.
diff --git a/packages/js/PATENTS b/packages/js/PATENTS
new file mode 100644
index 0000000..6954196
--- /dev/null
+++ b/packages/js/PATENTS
@@ -0,0 +1,23 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Dart Project.
+
+Google hereby grants to you a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this
+section) patent license to make, have made, use, offer to sell, sell,
+import, transfer, and otherwise run, modify and propagate the contents
+of this implementation of Dart, where such license applies only to
+those patent claims, both currently owned by Google and acquired in
+the future, licensable by Google that are necessarily infringed by
+this implementation of Dart. This grant does not include claims that
+would be infringed only as a consequence of further modification of
+this implementation. If you or your agent or exclusive licensee
+institute or order or agree to the institution of patent litigation
+against any entity (including a cross-claim or counterclaim in a
+lawsuit) alleging that this implementation of Dart or any code
+incorporated within this implementation of Dart constitutes direct or
+contributory patent infringement, or inducement of patent
+infringement, then any patent rights granted to you under this License
+for this implementation of Dart shall terminate as of the date such
+litigation is filed.
diff --git a/packages/js/README.md b/packages/js/README.md
new file mode 100644
index 0000000..3ba66d1
--- /dev/null
+++ b/packages/js/README.md
@@ -0,0 +1,107 @@
+Methods and annotations to specify interoperability with JavaScript APIs.
+
+*This packages requires Dart SDK 1.13.0.*
+
+*This is beta software. Please files [issues].*
+
+### Adding the dependency
+
+Add the following to your `pubspec.yaml`:
+
+```yaml
+dependencies:
+  js: ^0.6.0
+```
+
+### Example
+
+See the [Chart.js Dart API](https://github.com/google/chartjs.dart/) for an
+end-to-end example.
+
+### Usage
+
+#### Calling methods
+
+```dart
+// Calls invoke JavaScript `JSON.stringify(obj)`.
+@JS("JSON.stringify")
+external String stringify(obj);
+```
+
+#### Classes and Namespaces
+
+```dart
+@JS('google.maps')
+library maps;
+
+// Invokes the JavaScript getter `google.maps.map`.
+external Map get map;
+
+// `new Map` invokes JavaScript `new google.maps.Map(location)`
+@JS()
+class Map {
+  external Map(Location location);
+  external Location getLocation();
+}
+
+// `new Location(...)` invokes JavaScript `new google.maps.LatLng(...)`
+//
+// We recommend against using custom JavaScript names whenever
+// possible. It is easier for users if the JavaScript names and Dart names
+// are consistent.
+@JS("LatLng")
+class Location {
+  external Location(num lat, num lng);
+}
+```
+
+#### JavaScript object literals
+
+Many JavaScript APIs take an object literal as an argument. For example:
+```js
+// JavaScript
+printOptions({responsive: true});
+```
+
+If you want to use `printOptions` from Dart, you cannot simply pass a Dart `Map`
+object – they are are "opaque" in JavaScript.
+
+
+Instead, create a Dart class with both the `@JS()` and
+`@anonymous` annotations.
+
+```dart
+// Dart
+void main() {
+  printOptions(new Options(responsive: true));
+}
+
+@JS()
+external printOptions(Options options);
+
+@JS()
+@anonymous
+class Options {
+  external bool get responsive;
+
+  external factory Options({bool responsive});
+}
+```
+
+#### Passing functions to JavaScript.
+
+If you are passing a Dart function to a JavaScript API, you must wrap it using
+`allowInterop` or `allowInteropCaptureThis`.
+
+## Contributing and Filing Bugs
+
+Please file bugs and features requests on the [Github issue tracker][issues].
+
+We also love and accept community contributions, from API suggestions to pull requests.
+Please file an issue before beginning work so we can discuss the design and implementation.
+We are trying to create issues for all current and future work, so if something there intrigues you (or you need it!) join in on the discussion.
+
+Code contributors must sign the
+[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1).
+
+[issues]: https://goo.gl/j3rzs0
diff --git a/packages/js/example/README.md b/packages/js/example/README.md
new file mode 100644
index 0000000..6e5403e
--- /dev/null
+++ b/packages/js/example/README.md
@@ -0,0 +1 @@
+See the [Chart.js Dart API](https://github.com/google/chartjs.dart/) for a usage example.
diff --git a/packages/js/js.dart b/packages/js/lib/js.dart
similarity index 100%
rename from packages/js/js.dart
rename to packages/js/lib/js.dart
diff --git a/packages/js/src/varargs.dart b/packages/js/lib/src/varargs.dart
similarity index 100%
rename from packages/js/src/varargs.dart
rename to packages/js/lib/src/varargs.dart
diff --git a/packages/js/pubspec.yaml b/packages/js/pubspec.yaml
new file mode 100644
index 0000000..7555876
--- /dev/null
+++ b/packages/js/pubspec.yaml
@@ -0,0 +1,10 @@
+name: js
+version: 0.6.0
+authors:
+- Dart Team <misc@dartlang.org>
+description: Access JavaScript from Dart.
+homepage: https://github.com/dart-lang/sdk/tree/master/pkg/js
+environment:
+  sdk: '>=1.13.0 <2.0.0'
+dev_dependencies:
+  browser: '^0.10.0+2'
diff --git a/packages/js_util/.gitignore b/packages/js_util/.gitignore
new file mode 100644
index 0000000..4e73421
--- /dev/null
+++ b/packages/js_util/.gitignore
@@ -0,0 +1,22 @@
+# Files and directories created by pub
+.packages
+.pub/
+build/
+packages
+pubspec.lock
+
+# Files created by dart2js
+*.dart.js
+*.part.js
+*.js.deps
+*.js.map
+*.info.json
+
+# Directory created by dartdoc
+doc/
+
+# JetBrains IDEs
+.idea/
+*.iml
+*.ipr
+*.iws
diff --git a/packages/js_util/.travis.yml b/packages/js_util/.travis.yml
new file mode 100644
index 0000000..f3fa6c3
--- /dev/null
+++ b/packages/js_util/.travis.yml
@@ -0,0 +1,12 @@
+language: dart
+sudo: false
+dart:
+  - stable
+  - dev
+with_content_shell: true
+before_install:
+  - export DISPLAY=:99.0
+  - sh -e /etc/init.d/xvfb start
+script: ./tool/travis.sh
+env:
+  - DARTANALYZER_FLAGS=--fatal-warnings
diff --git a/packages/js_util/CHANGELOG.md b/packages/js_util/CHANGELOG.md
new file mode 100644
index 0000000..995eb98
--- /dev/null
+++ b/packages/js_util/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Changelog
+
+## 0.2.0
+
+- Add @JS annotations on library directives to support 1.16.0
+- Add the minified version of js_util.js
+
+## 0.1.0
+
+- Initial version
diff --git a/packages/js_util/LICENSE b/packages/js_util/LICENSE
new file mode 100644
index 0000000..906df54
--- /dev/null
+++ b/packages/js_util/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2016, Fluidic 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 the <organization> 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 <COPYRIGHT HOLDER> 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.
diff --git a/packages/js_util/README.md b/packages/js_util/README.md
new file mode 100644
index 0000000..412af74
--- /dev/null
+++ b/packages/js_util/README.md
@@ -0,0 +1,69 @@
+# js_util
+
+[![Build Status](https://travis-ci.org/fluidic/js_util.svg?branch=master)](https://travis-ci.org/fluidic/js_util)
+
+Utilities to access JavaScript from Dart.
+
+* toJS(o): Converts a Dart object to a JavaScript object.
+* newObject(): Creates a new JavaScript object.
+* defineProperty(o, String prop, PropertyDescription desc): A wrapper for [Object.defineProperty][defineProperty]
+* getValue(o, String prop): Returns `o[prop]`.
+* setValue(o, String prop, value): Performs `o[prop] = value`.
+
+These utilities are of great help if a JavaScript API takes a JavaScript object
+with keys that are not fixed because [js][js] package does not let you create a
+JavaScript object without declaring a Dart class with `@JS()` and `@anonymous`.
+
+[defineProperty]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
+[js]: https://pub.dartlang.org/packages/js
+
+## Getting Started
+
+Include `js_util.js` in index.html to use js_util functions.
+
+```html
+<html>
+  <head>
+    <script async src="packages/js_util/dist/js_util.js"></script>
+    <script async src="packages/browser/dart.js"></script>
+  </head>
+</html>
+```
+
+## Usage
+
+A simple usage example:
+
+```dart
+final obj = newObject();
+defineProperty(obj, 'foo', new PropertyDescription(enumerable: true, value: 1));
+defineProperty(obj, 'bar', new PropertyDescription(enumerable: false, value: 2));
+```
+
+```dart
+final obj = newObject();
+setValue(obj, 'foo', 1);
+setValue(obj, 'bar', 2);
+
+print(getValue(obj, 'foo')); // 1
+print(getValue(obj, 'bar')); // 2
+```
+
+```dart
+final jsObj = toJS({
+  'people': [
+    {'firstName': 'Kwang Yul', 'lastName': 'Seo'},
+    {'firstName': 'DoHyung', 'lastName': 'Kim'},
+    {'firstName': 'Kyusun', 'lastName': 'Kim'}
+  ]
+});
+
+final people = getValue(jsObj, 'people');
+print(getValue(people[0], 'firstName')); // 'Kwang Yul'
+```
+
+## Features and bugs
+
+Please file feature requests and bugs at the [issue tracker][tracker].
+
+[tracker]: https://github.com/ProtoCatTeam/js_util/issues
diff --git a/packages/js_util/example/js_util.dart b/packages/js_util/example/js_util.dart
new file mode 100644
index 0000000..ce87db1
--- /dev/null
+++ b/packages/js_util/example/js_util.dart
@@ -0,0 +1,20 @@
+import 'dart:html';
+
+import 'package:js_util/js_util.dart';
+
+void main() {
+  final jsObj = toJS({
+    'people': [
+      {'firstName': 'Kwang Yul', 'lastName': 'Seo'},
+      {'firstName': 'DoHyung', 'lastName': 'Kim'},
+      {'firstName': 'Kyusun', 'lastName': 'Kim'}
+    ]
+  });
+
+  final people = getValue(jsObj, 'people');
+  final firstPerson = people[0];
+  final text =
+      '${getValue(firstPerson, "firstName")} ${getValue(firstPerson, "lastName")}';
+  document.querySelector('#container').innerHtml = text;
+}
+
diff --git a/packages/js_util/example/js_util.html b/packages/js_util/example/js_util.html
new file mode 100644
index 0000000..1a26173
--- /dev/null
+++ b/packages/js_util/example/js_util.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>js_util Demo</title>
+    <script src="packages/js_util/dist/js_util.js"></script>
+    <script async src="packages/browser/dart.js"></script>
+  </head>
+  <body>
+    <h1>js_util Demo</h1>
+
+    <div id="container"></div>
+
+    <script async type="application/dart" src="js_util.dart"></script>
+  </body>
+</html>
diff --git a/packages/js_util/dist/js_util.js b/packages/js_util/lib/dist/js_util.js
similarity index 100%
rename from packages/js_util/dist/js_util.js
rename to packages/js_util/lib/dist/js_util.js
diff --git a/packages/js_util/dist/js_util.min.js b/packages/js_util/lib/dist/js_util.min.js
similarity index 100%
rename from packages/js_util/dist/js_util.min.js
rename to packages/js_util/lib/dist/js_util.min.js
diff --git a/packages/js_util/js_util.dart b/packages/js_util/lib/js_util.dart
similarity index 100%
rename from packages/js_util/js_util.dart
rename to packages/js_util/lib/js_util.dart
diff --git a/packages/js_util/src/js_util_base.dart b/packages/js_util/lib/src/js_util_base.dart
similarity index 100%
rename from packages/js_util/src/js_util_base.dart
rename to packages/js_util/lib/src/js_util_base.dart
diff --git a/packages/js_util/pubspec.yaml b/packages/js_util/pubspec.yaml
new file mode 100644
index 0000000..fc54d80
--- /dev/null
+++ b/packages/js_util/pubspec.yaml
@@ -0,0 +1,16 @@
+name: js_util
+description: Utilities to access JavaScript from Dart.
+version: 0.2.0
+author: Fluidic Team <dev@fluidic.io>
+homepage: https://github.com/fluidic/js_util
+
+environment:
+  sdk: '>=1.8.0 <2.0.0'
+
+dependencies:
+  js: '>=0.6.0 <0.7.0'
+  quiver_iterables: '>=1.0.0 <2.0.0'
+
+dev_dependencies:
+  browser: '>=0.10.0 <0.11.0'
+  test: '>=0.12.0 <0.13.0'
diff --git a/packages/js_util/test/js_util_test.dart b/packages/js_util/test/js_util_test.dart
new file mode 100644
index 0000000..8252c23
--- /dev/null
+++ b/packages/js_util/test/js_util_test.dart
@@ -0,0 +1,50 @@
+@JS()
+library js_util.test;
+
+import 'package:js/js.dart';
+import 'package:js_util/js_util.dart';
+import 'package:test/test.dart';
+
+@JS('JSON.stringify')
+external String stringify(Object json);
+
+void main() {
+  group('js_util tests', () {
+    test('defineProperty test', () {
+      final obj = newObject();
+      defineProperty(
+          obj, 'foo', new PropertyDescription(enumerable: true, value: 1));
+      defineProperty(
+          obj, 'bar', new PropertyDescription(enumerable: false, value: 2));
+
+      expect(stringify(obj), '{"foo":1}');
+    });
+
+    test('newObject/setValue/getValue test', () {
+      final obj = newObject();
+      setValue(obj, 'foo', 1);
+      setValue(obj, 'bar', 2);
+
+      expect(getValue(obj, 'foo'), equals(1));
+      expect(getValue(obj, 'bar'), equals(2));
+    });
+
+    test('toJS test', () {
+      final jsObj = toJS({
+        'people': [
+          {'firstName': 'Kwang Yul', 'lastName': 'Seo'},
+          {'firstName': 'DoHyung', 'lastName': 'Kim'},
+          {'firstName': 'Kyusun', 'lastName': 'Kim'}
+        ]
+      });
+
+      final people = getValue(jsObj, 'people');
+      expect(getValue(people[0], 'firstName'), equals('Kwang Yul'));
+      expect(getValue(people[0], 'lastName'), equals('Seo'));
+      expect(getValue(people[1], 'firstName'), equals('DoHyung'));
+      expect(getValue(people[1], 'lastName'), equals('Kim'));
+      expect(getValue(people[2], 'firstName'), equals('Kyusun'));
+      expect(getValue(people[2], 'lastName'), equals('Kim'));
+    });
+  });
+}
diff --git a/packages/js_util/test/js_util_test.html b/packages/js_util/test/js_util_test.html
new file mode 100644
index 0000000..42b369d
--- /dev/null
+++ b/packages/js_util/test/js_util_test.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <link rel="x-dart-test" href="js_util_test.dart">
+    <script src="packages/js_util/dist/js_util.js"></script>
+    <script src="packages/test/dart.js"></script>
+</head>
+<body>
+</body>
+</html>
\ No newline at end of file
diff --git a/packages/js_util/tool/travis.sh b/packages/js_util/tool/travis.sh
new file mode 100755
index 0000000..466fa45
--- /dev/null
+++ b/packages/js_util/tool/travis.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Copyright (c) 2015, Google Inc. 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.
+
+# Fast fail the script on failures.
+set -e
+
+# Verify that the libraries are error and warning-free.
+echo "Running dartanalyzer..."
+libs=$(find lib -maxdepth 1 -type f -name '*.dart')
+dartanalyzer $DARTANALYZER_FLAGS $libs test/js_util_test.dart
+
+# Run the tests.
+echo "Running tests..."
+pub run test:test -p content-shell
diff --git a/packages/quiver_iterables/.gitattributes b/packages/quiver_iterables/.gitattributes
new file mode 100644
index 0000000..b0a6c1c
--- /dev/null
+++ b/packages/quiver_iterables/.gitattributes
@@ -0,0 +1,2 @@
+# Ensure line-endings are normalized to LF
+* text=auto
diff --git a/packages/quiver_iterables/.gitignore b/packages/quiver_iterables/.gitignore
new file mode 100644
index 0000000..dcc1376
--- /dev/null
+++ b/packages/quiver_iterables/.gitignore
@@ -0,0 +1,15 @@
+# Pub
+.packages
+.pub
+build/
+packages
+pubspec.lock
+
+# IDE
+.idea
+.project
+.settings
+*.iml
+
+# Temp files
+*~
diff --git a/packages/quiver_iterables/.travis.yml b/packages/quiver_iterables/.travis.yml
new file mode 100644
index 0000000..a4a70c4
--- /dev/null
+++ b/packages/quiver_iterables/.travis.yml
@@ -0,0 +1,8 @@
+language: dart
+sudo: false
+dart:
+  - stable
+  - dev
+script: ./tool/travis.sh
+env:
+  - DARTANALYZER_FLAGS=--fatal-warnings
diff --git a/packages/quiver_iterables/CHANGELOG.md b/packages/quiver_iterables/CHANGELOG.md
new file mode 100644
index 0000000..824135d
--- /dev/null
+++ b/packages/quiver_iterables/CHANGELOG.md
@@ -0,0 +1,2 @@
+#### 1.0.0-dev.1
+   * Split from `quiver-dart`
diff --git a/packages/quiver_iterables/CONTRIBUTING.md b/packages/quiver_iterables/CONTRIBUTING.md
new file mode 100644
index 0000000..a1368e8
--- /dev/null
+++ b/packages/quiver_iterables/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# How to contribute
+
+### Sign our Contributor License Agreement (CLA)
+
+Even for small changes, we ask that you please sign the CLA electronically
+[here](https://developers.google.com/open-source/cla/individual).
+The CLA is necessary because you own the copyright to your changes, even
+after your contribution becomes part of our codebase, so we need your permission
+to use and distribute your code. You can find more details
+[here](https://code.google.com/p/dart/wiki/Contributing). You'll only need to
+do this once.
+
+### Contribution Guidelines
+
+We welcome your pull requests, issue reports and enhancement requests. To make
+the process as smooth as possible, we request the following:
+
+   * Sign the [CLA](https://cla.developers.google.com/about/google-individual)
+     (see above) before sending your pull request. It's quick, we promise!
+   * Have test cases for your changes and ensure that the existing ones pass in
+     checked mode.
+   * Run your changes through `dartfmt`. Follow the installation instructions
+     in the [dart_style](https://github.com/dart-lang/dart_style) README for
+     more info.
+   * Squash your commits into a single commit with a good description. You can
+     use `git rebase -i` for this. For more details on rebasing, check out
+     Atlassian's
+     [tutorial](https://www.atlassian.com/git/tutorials/rewriting-history).
+   * During code review, go ahead and pile up commits addressing review
+     comments. Once you get an LGTM (looks good to me) on the review, we'll ask
+     you to squash your commits one last time, then we'll be good to merge!
diff --git a/packages/quiver_iterables/LICENSE b/packages/quiver_iterables/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/packages/quiver_iterables/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/packages/quiver_iterables/README.md b/packages/quiver_iterables/README.md
new file mode 100644
index 0000000..d9c4dc4
--- /dev/null
+++ b/packages/quiver_iterables/README.md
@@ -0,0 +1,25 @@
+Quiver Iterables
+================
+
+A collection of utilities for generating and manipulating Dart Iterables.
+
+[![Build Status](https://travis-ci.org/QuiverDart/quiver_iterables.svg?branch=master)](https://travis-ci.org/QuiverDart/quiver_iterables)
+[![Coverage Status](https://img.shields.io/coveralls/QuiverDart/quiver_iterables.svg)](https://coveralls.io/r/QuiverDart/quiver_iterables)
+
+## Documentation
+
+[API Docs](http://www.dartdocs.org/documentation/quiver_iterables/latest)
+
+`concat`, `count`, `cycle`, `enumerate`, `merge`, `partition`, `range`, and
+`zip` create, transform, or combine Iterables in different ways, similar to
+Python's itertools.
+
+`min`, `max`, and `extent` retrieve the minimum and maximum elements from an
+iterable.
+
+`GeneratingIterable` is an easy way to create lazy iterables that produce
+elements by calling a function. A common use-case is to traverse properties in
+an object graph, like the parent relationship in a tree.
+
+`InfiniteIterable` is a base class for Iterables that throws on operations that
+require a finite length.
diff --git a/packages/quiver_iterables/lib/iterables.dart b/packages/quiver_iterables/lib/iterables.dart
new file mode 100644
index 0000000..26130bd
--- /dev/null
+++ b/packages/quiver_iterables/lib/iterables.dart
@@ -0,0 +1,29 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables;
+
+import 'dart:collection';
+
+part 'src/concat.dart';
+part 'src/count.dart';
+part 'src/cycle.dart';
+part 'src/enumerate.dart';
+part 'src/infinite_iterable.dart';
+part 'src/merge.dart';
+part 'src/min_max.dart';
+part 'src/partition.dart';
+part 'src/generating_iterable.dart';
+part 'src/range.dart';
+part 'src/zip.dart';
diff --git a/packages/quiver_iterables/lib/src/concat.dart b/packages/quiver_iterables/lib/src/concat.dart
new file mode 100644
index 0000000..e32c269
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/concat.dart
@@ -0,0 +1,20 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns the concatentation of the input iterables.
+///
+/// The returned iterable is a lazily-evaluated view on the input iterables.
+Iterable concat(Iterable<Iterable> iterables) => iterables.expand((x) => x);
diff --git a/packages/quiver_iterables/lib/src/count.dart b/packages/quiver_iterables/lib/src/count.dart
new file mode 100644
index 0000000..093423a
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/count.dart
@@ -0,0 +1,24 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns an infinite [Iterable] of [num]s, starting from [start] and
+/// increasing by [step].
+Iterable<num> count([num start = 0, num step = 1]) sync* {
+  while (true) {
+    yield start;
+    start += step;
+  }
+}
diff --git a/packages/quiver_iterables/lib/src/cycle.dart b/packages/quiver_iterables/lib/src/cycle.dart
new file mode 100644
index 0000000..7f1614d
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/cycle.dart
@@ -0,0 +1,52 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns an [Iterable] that infinitely cycles through the elements of
+/// [iterable]. If [iterable] is empty, the returned Iterable will also be empty.
+Iterable cycle(Iterable iterable) => new _Cycle(iterable);
+
+class _Cycle<T> extends InfiniteIterable<T> {
+  final Iterable<T> _iterable;
+
+  _Cycle(this._iterable);
+
+  Iterator<T> get iterator => new _CycleIterator(_iterable);
+
+  bool get isEmpty => _iterable.isEmpty;
+
+  bool get isNotEmpty => _iterable.isNotEmpty;
+
+  // TODO(justin): add methods that can be answered by the wrapped iterable
+}
+
+class _CycleIterator<T> implements Iterator<T> {
+  final Iterable<T> _iterable;
+  Iterator<T> _iterator;
+
+  _CycleIterator(_iterable)
+      : _iterable = _iterable,
+        _iterator = _iterable.iterator;
+
+  T get current => _iterator.current;
+
+  bool moveNext() {
+    if (!_iterator.moveNext()) {
+      _iterator = _iterable.iterator;
+      return _iterator.moveNext();
+    }
+    return true;
+  }
+}
diff --git a/packages/quiver_iterables/lib/src/enumerate.dart b/packages/quiver_iterables/lib/src/enumerate.dart
new file mode 100644
index 0000000..b0f8e40
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/enumerate.dart
@@ -0,0 +1,74 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns an [Iterable] of [IndexedValue]s where the nth value holds the nth
+/// element of [iterable] and its index.
+Iterable<IndexedValue> enumerate(Iterable iterable) =>
+    new EnumerateIterable(iterable);
+
+class IndexedValue<V> {
+  final int index;
+  final V value;
+
+  IndexedValue(this.index, this.value);
+
+  operator ==(o) => o is IndexedValue && o.index == index && o.value == value;
+  int get hashCode => index * 31 + value.hashCode;
+  String toString() => '($index, $value)';
+}
+
+/// An [Iterable] of [IndexedValue]s where the nth value holds the nth
+/// element of [iterable] and its index. See [enumerate].
+// This was inspired by MappedIterable internal to Dart collections.
+class EnumerateIterable<V> extends IterableBase<IndexedValue<V>> {
+  final Iterable<V> _iterable;
+
+  EnumerateIterable(this._iterable);
+
+  Iterator<IndexedValue<V>> get iterator =>
+      new EnumerateIterator<V>(_iterable.iterator);
+
+  // Length related functions are independent of the mapping.
+  int get length => _iterable.length;
+  bool get isEmpty => _iterable.isEmpty;
+
+  // Index based lookup can be done before transforming.
+  IndexedValue<V> get first => new IndexedValue<V>(0, _iterable.first);
+  IndexedValue<V> get last => new IndexedValue<V>(length - 1, _iterable.last);
+  IndexedValue<V> get single => new IndexedValue<V>(0, _iterable.single);
+  IndexedValue<V> elementAt(int index) =>
+      new IndexedValue<V>(index, _iterable.elementAt(index));
+}
+
+/// The [Iterator] returned by [EnumerateIterable.iterator].
+class EnumerateIterator<V> extends Iterator<IndexedValue<V>> {
+  final Iterator<V> _iterator;
+  int _index = 0;
+  IndexedValue<V> _current;
+
+  EnumerateIterator(this._iterator);
+
+  IndexedValue<V> get current => _current;
+
+  bool moveNext() {
+    if (_iterator.moveNext()) {
+      _current = new IndexedValue(_index++, _iterator.current);
+      return true;
+    }
+    _current = null;
+    return false;
+  }
+}
diff --git a/packages/quiver_iterables/lib/src/generating_iterable.dart b/packages/quiver_iterables/lib/src/generating_iterable.dart
new file mode 100644
index 0000000..13041a6
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/generating_iterable.dart
@@ -0,0 +1,74 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+Iterable generate(initial(), next(o)) => new GeneratingIterable(initial, next);
+
+/// An Iterable who's first value is [object] and who's subsequent values are
+/// generated by passing the current value to the [next] function.
+///
+/// The class is useful for creating lazy iterables from object hierarchies and
+/// graphs.
+///
+/// It's important that for the given initial value and next function that the
+/// sequence of items eventually terminates. Otherwise calling methods that
+/// expect a finite sequence, like `length` or `last`, will cause an infinite
+/// loop.
+///
+/// Example:
+///
+///     class Node {
+///       Node parent;
+///
+///       /// An iterable of node and all ancestors up to the root.
+///       Iterable<Node> ancestors =
+///           new GeneratingIterable<Node>(() => this, (n) => n.parent);
+///
+///       /// An iterable of the root and the path of nodes to this. The
+///       /// reverse of ancestors.
+///       Iterable<Node> path = ancestors.toList().reversed();
+///     }
+///
+class GeneratingIterable<T> extends IterableBase<T> {
+  final initial;
+  final next;
+
+  GeneratingIterable(T this.initial(), T this.next(T o));
+
+  @override
+  Iterator<T> get iterator => new _GeneratingIterator(initial(), next);
+}
+
+class _GeneratingIterator<T> implements Iterator<T> {
+  final next;
+  T object;
+  bool started = false;
+
+  _GeneratingIterator(T this.object, T this.next(T o));
+
+  @override
+  T get current => started ? object : null;
+
+  @override
+  bool moveNext() {
+    if (object == null) return false;
+    if (started) {
+      object = next(object);
+    } else {
+      started = true;
+    }
+    return object != null;
+  }
+}
diff --git a/packages/quiver_iterables/lib/src/infinite_iterable.dart b/packages/quiver_iterables/lib/src/infinite_iterable.dart
new file mode 100644
index 0000000..69085ea
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/infinite_iterable.dart
@@ -0,0 +1,48 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// A base class for [Iterable]s of infinite length that throws
+/// [UnsupportedError] for methods that would require the Iterable to terminate.
+abstract class InfiniteIterable<T> extends IterableBase<T> {
+  bool get isEmpty => false;
+
+  bool get isNotEmpty => true;
+
+  T get last => throw new UnsupportedError('last');
+
+  int get length => throw new UnsupportedError('length');
+
+  T get single => throw new StateError('single');
+
+  bool every(bool f(T element)) => throw new UnsupportedError('every');
+
+  bool fold(initialValue, combine(previousValue, T element)) =>
+      throw new UnsupportedError('fold');
+
+  void forEach(void f(T element)) => throw new UnsupportedError('forEach');
+
+  String join([String separator = '']) => throw new UnsupportedError('join');
+
+  T lastWhere(bool test(T value), {T orElse()}) =>
+      throw new UnsupportedError('lastWhere');
+
+  T reduce(T combine(T value, T element)) =>
+      throw new UnsupportedError('reduce');
+
+  List<T> toList({bool growable: true}) => throw new UnsupportedError('toList');
+
+  Set<T> toSet() => throw new UnsupportedError('toSet');
+}
diff --git a/packages/quiver_iterables/lib/src/merge.dart b/packages/quiver_iterables/lib/src/merge.dart
new file mode 100644
index 0000000..99466e3
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/merge.dart
@@ -0,0 +1,87 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns the result of merging an [Iterable] of [Iterable]s, according to
+/// the order specified by the [compare] function. This function assumes the
+/// provided iterables are already sorted according to the provided [compare]
+/// function. It will not check for this condition or sort the iterables.
+///
+/// The compare function must act as a [Comparator]. If [compare] is omitted,
+/// [Comparable.compare] is used.
+///
+/// If any of the [iterables] contain null elements, an exception will be
+/// thrown.
+Iterable merge(Iterable<Iterable> iterables,
+        [Comparator compare = Comparable.compare]) =>
+    (iterables.isEmpty) ? const [] : new _Merge(iterables, compare);
+
+class _Merge extends IterableBase {
+  final Iterable<Iterable> _iterables;
+  final Comparator _compare;
+
+  _Merge(this._iterables, this._compare);
+
+  Iterator get iterator => new _MergeIterator(
+      _iterables.map((i) => i.iterator).toList(growable: false), _compare);
+
+  String toString() => this.toList().toString();
+}
+
+/// Like [Iterator] but one element ahead.
+class _IteratorPeeker {
+  final Iterator _iterator;
+  bool _hasCurrent;
+
+  _IteratorPeeker(Iterator iterator)
+      : _iterator = iterator,
+        _hasCurrent = iterator.moveNext();
+
+  moveNext() {
+    _hasCurrent = _iterator.moveNext();
+  }
+
+  get current => _iterator.current;
+}
+
+class _MergeIterator implements Iterator {
+  final List<_IteratorPeeker> _peekers;
+  final Comparator _compare;
+  var _current;
+
+  _MergeIterator(List<Iterator> iterators, this._compare)
+      : _peekers = iterators.map((i) => new _IteratorPeeker(i)).toList();
+
+  bool moveNext() {
+    // Pick the peeker that's peeking at the puniest piece
+    _IteratorPeeker minIter = null;
+    for (var p in _peekers) {
+      if (p._hasCurrent) {
+        if (minIter == null || _compare(p.current, minIter.current) < 0) {
+          minIter = p;
+        }
+      }
+    }
+
+    if (minIter == null) {
+      return false;
+    }
+    _current = minIter.current;
+    minIter.moveNext();
+    return true;
+  }
+
+  get current => _current;
+}
diff --git a/packages/quiver_iterables/lib/src/min_max.dart b/packages/quiver_iterables/lib/src/min_max.dart
new file mode 100644
index 0000000..41ef95a
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/min_max.dart
@@ -0,0 +1,63 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns the maximum value in [i], according to the order specified by the
+/// [compare] function, or `null` if [i] is empty.
+///
+/// The compare function must act as a [Comparator]. If [compare] is omitted,
+/// [Comparable.compare] is used. If [i] contains null elements, an exception
+/// will be thrown.
+///
+dynamic max(Iterable i, [Comparator compare = Comparable.compare]) =>
+    i.isEmpty ? null : i.reduce((a, b) => compare(a, b) > 0 ? a : b);
+
+/// Returns the minimum value in [i], according to the order specified by the
+/// [compare] function, or `null` if [i] is empty.
+///
+/// The compare function must act as a [Comparator]. If [compare] is omitted,
+/// [Comparable.compare] is used. If [i] contains null elements, an exception
+/// will be thrown.
+dynamic min(Iterable i, [Comparator compare = Comparable.compare]) =>
+    i.isEmpty ? null : i.reduce((a, b) => compare(a, b) < 0 ? a : b);
+
+/// Returns the minimum and maximum values in [i], according to the order
+/// specified by the [compare] function, in an [Extent] instance. Always returns
+/// an [Extent], but [Extent.min] and [Extent.max] may be `null` if [i] is empty.
+///
+/// The compare function must act as a [Comparator]. If [compare] is omitted,
+/// [Comparable.compare] is used. If [i] contains null elements, an exception
+/// will be thrown.
+///
+/// If [i] is empty, an [Extent] is returned with [:null:] values for [:min:] and
+/// [:max:], since there are no valid values for them.
+Extent extent(Iterable i, [Comparator compare = Comparable.compare]) {
+  var iterator = i.iterator;
+  var hasNext = iterator.moveNext();
+  if (!hasNext) return new Extent(null, null);
+  var max = iterator.current;
+  var min = iterator.current;
+  while (iterator.moveNext()) {
+    if (compare(max, iterator.current) < 0) max = iterator.current;
+    if (compare(min, iterator.current) > 0) min = iterator.current;
+  }
+  return new Extent(min, max);
+}
+
+class Extent {
+  final min;
+  final max;
+  Extent(this.min, this.max);
+}
diff --git a/packages/quiver_iterables/lib/src/partition.dart b/packages/quiver_iterables/lib/src/partition.dart
new file mode 100644
index 0000000..626c587
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/partition.dart
@@ -0,0 +1,44 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Partitions the input iterable into lists of the specified size.
+Iterable<List> partition(Iterable iterable, int size) {
+  if (size <= 0) throw new ArgumentError(size);
+  return _partition(iterable, size);
+}
+
+Iterable<List> _partition(Iterable iterable, int size) sync* {
+  if (iterable.isEmpty) return;
+  var iterator = iterable.iterator;
+  iterator.moveNext();
+  var first = iterator.current;
+  while (true) {
+    var part = [first];
+    for (var i = 0; i < size - 1; i++) {
+      if (!iterator.moveNext()) {
+        yield part;
+        return;
+      }
+      part.add(iterator.current);
+    }
+    yield part;
+    if (iterator.moveNext()) {
+      first = iterator.current;
+    } else {
+      return;
+    }
+  }
+}
diff --git a/packages/quiver_iterables/lib/src/range.dart b/packages/quiver_iterables/lib/src/range.dart
new file mode 100644
index 0000000..bb45a89
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/range.dart
@@ -0,0 +1,50 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns an [Iterable] sequence of [num]s.
+///
+/// If only one argument is provided, [start_or_stop] is the upper bound for the
+/// sequence. If two or more arguments are provided, [stop] is the upper bound.
+///
+/// The sequence starts at 0 if one argument is provided, or [start_or_stop] if
+/// two or more arguments are provided. The sequence increments by 1, or [step]
+/// if provided. [step] can be negative, in which case the sequence counts down
+/// from the starting point and [stop] must be less than the starting point so
+/// that it becomes the lower bound.
+Iterable<num> range(num start_or_stop, [num stop, num step]) {
+  var start = (stop == null) ? 0 : start_or_stop;
+  stop = (stop == null) ? start_or_stop : stop;
+  step = (step == null) ? 1 : step;
+  if (step == 0) {
+    throw new ArgumentError("step cannot be 0");
+  }
+  if ((step > 0) && (stop < start)) {
+    throw new ArgumentError("if step is positive,"
+        " stop must be greater than start");
+  }
+  if ((step < 0) && (stop > start)) {
+    throw new ArgumentError("if step is negative,"
+        " stop must be less than start");
+  }
+  return _range(start, stop, step);
+}
+
+Iterable<num> _range(num start, num stop, num step) sync* {
+  while (step < 0 ? start > stop : start < stop) {
+    yield start;
+    start += step;
+  }
+}
diff --git a/packages/quiver_iterables/lib/src/zip.dart b/packages/quiver_iterables/lib/src/zip.dart
new file mode 100644
index 0000000..6e8d81b
--- /dev/null
+++ b/packages/quiver_iterables/lib/src/zip.dart
@@ -0,0 +1,32 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+part of quiver.iterables;
+
+/// Returns an [Iterable] of [List]s where the nth element in the returned
+/// iterable contains the nth element from every Iterable in [iterables]. The
+/// returned Iterable is as long as the shortest Iterable in the argument. If
+/// [iterables] is empty, it returns an empty list.
+Iterable<List> zip(Iterable<Iterable> iterables) sync* {
+  if (iterables.isEmpty) return;
+  var iterators = iterables.map((i) => i.iterator).toList(growable: false);
+  while (true) {
+    var zipped = new List(iterators.length);
+    for (var i = 0; i < zipped.length; i++) {
+      if (!iterators[i].moveNext()) return;
+      zipped[i] = iterators[i].current;
+    }
+    yield zipped;
+  }
+}
diff --git a/packages/quiver_iterables/pubspec.yaml b/packages/quiver_iterables/pubspec.yaml
new file mode 100644
index 0000000..9a69d2a
--- /dev/null
+++ b/packages/quiver_iterables/pubspec.yaml
@@ -0,0 +1,19 @@
+name: quiver_iterables
+version: 1.0.0
+authors:
+- Justin Fagnani <justinfagnani@google.com>
+- Yegor Jbanov <yjbanov@google.com>
+- Chris Bracken <cbracken@google.com>
+- Alexandre Ardhuin <alexandre.ardhuin@gmail.com>
+- David Morgan <davidmorgan@google.com>
+- John McDole <codefu@google.com>
+- Matan Lurey <matanl@google.com>
+- Günter Zöchbauer <guenter@gzoechbauer.com>
+- Sean Eagan <seaneagan1@gmail.com>
+- Victor Berchet <victor@suumit.com>
+description: Utilities for working with iterables
+homepage: https://github.com/QuiverDart/quiver_iterables
+environment:
+  sdk: '>=1.9.0 <2.0.0'
+dev_dependencies:
+  test: '>=0.12.0 <0.13.0'
diff --git a/packages/quiver_iterables/test/all_tests.dart b/packages/quiver_iterables/test/all_tests.dart
new file mode 100644
index 0000000..f023455
--- /dev/null
+++ b/packages/quiver_iterables/test/all_tests.dart
@@ -0,0 +1,37 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import 'concat_test.dart' as concat_test;
+import 'count_test.dart' as count_test;
+import 'cycle_test.dart' as cycle_test;
+import 'enumerate_test.dart' as enumerate_test;
+import 'generating_iterable_test.dart' as generating_iterable_test;
+import 'merge_test.dart' as merge_test;
+import 'min_max_test.dart' as min_max_test;
+import 'partition_test.dart' as partition_test;
+import 'range_test.dart' as range_test;
+import 'zip_test.dart' as zip_test;
+
+main() {
+  concat_test.main();
+  count_test.main();
+  cycle_test.main();
+  enumerate_test.main();
+  generating_iterable_test.main();
+  merge_test.main();
+  min_max_test.main();
+  partition_test.main();
+  range_test.main();
+  zip_test.main();
+}
diff --git a/packages/quiver_iterables/test/concat_test.dart b/packages/quiver_iterables/test/concat_test.dart
new file mode 100644
index 0000000..788fbda
--- /dev/null
+++ b/packages/quiver_iterables/test/concat_test.dart
@@ -0,0 +1,67 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.concat_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('concat', () {
+    test('should handle empty input iterables', () {
+      expect(concat([]), isEmpty);
+    });
+
+    test('should handle single input iterables', () {
+      expect(
+          concat([
+            [1, 2, 3]
+          ]),
+          [1, 2, 3]);
+    });
+
+    test('should chain multiple input iterables', () {
+      expect(
+          concat([
+            [1, 2, 3],
+            [-1, -2, -3]
+          ]),
+          [1, 2, 3, -1, -2, -3]);
+    });
+
+    test('should throw for null input', () {
+      expect(() => concat(null), throws);
+    });
+
+    test('should throw if any input is null', () {
+      expect(
+          () => concat([
+                [1, 2],
+                null,
+                [3, 4]
+              ]).toList(),
+          throws);
+    });
+
+    test('should reflectchanges in the inputs', () {
+      var a = [1, 2];
+      var b = [4, 5];
+      var ab = concat([a, b]);
+      expect(ab, [1, 2, 4, 5]);
+      a.add(3);
+      b.add(6);
+      expect(ab, [1, 2, 3, 4, 5, 6]);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/count_test.dart b/packages/quiver_iterables/test/count_test.dart
new file mode 100644
index 0000000..aa40be3
--- /dev/null
+++ b/packages/quiver_iterables/test/count_test.dart
@@ -0,0 +1,39 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.count_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('count', () {
+    test("should create an infinite sequence starting at 0 given no args", () {
+      expect(count().first, 0);
+      expect(count().take(5), [0, 1, 2, 3, 4]);
+    });
+
+    test("should create an infinite sequence starting from start", () {
+      expect(count(3).first, 3);
+      expect(count(3).take(5), [3, 4, 5, 6, 7]);
+    });
+
+    test("should create an infinite sequence stepping by step", () {
+      expect(count(3, 2).first, 3);
+      expect(count(3, 2).take(5), [3, 5, 7, 9, 11]);
+      expect(count(3.5, 2).first, 3.5);
+      expect(count(3.5, .5).take(5), [3.5, 4, 4.5, 5, 5.5]);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/cycle_test.dart b/packages/quiver_iterables/test/cycle_test.dart
new file mode 100644
index 0000000..4890c7f
--- /dev/null
+++ b/packages/quiver_iterables/test/cycle_test.dart
@@ -0,0 +1,34 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.cycle_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('cycle', () {
+    test("should create an empty iterable given an empty iterable", () {
+      expect(cycle([]), []);
+      expect(cycle([]).isEmpty, true);
+      expect(cycle([]).isNotEmpty, false);
+    });
+
+    test("should cycle its argument", () {
+      expect(cycle([1, 2, 3]).take(7), [1, 2, 3, 1, 2, 3, 1]);
+      expect(cycle([1, 2, 3]).isEmpty, false);
+      expect(cycle([1, 2, 3]).isNotEmpty, true);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/enumerate_test.dart b/packages/quiver_iterables/test/enumerate_test.dart
new file mode 100644
index 0000000..96b79ba
--- /dev/null
+++ b/packages/quiver_iterables/test/enumerate_test.dart
@@ -0,0 +1,86 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.enumerate_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('enumerate', () {
+    test("should add indices to its argument", () {
+      var e = enumerate(['a', 'b', 'c']);
+      expect(e.map((v) => v.index), [0, 1, 2]);
+      expect(e.map((v) => v.value), ['a', 'b', 'c']);
+    });
+
+    test("should return an empty iterable given an empty iterable", () {
+      expect(enumerate([]), []);
+    });
+
+    test("should add indices to its argument", () {
+      var e = enumerate(['a', 'b', 'c']);
+      expect(e.map((v) => v.index), [0, 1, 2]);
+      expect(e.map((v) => v.index), [0, 1, 2],
+          reason: 'should enumerate to the same values a second time');
+    });
+
+    test("first", () {
+      var e = enumerate(['a', 'b', 'c']);
+      expect(e.first.value, 'a');
+      expect(e.first.index, 0);
+      expect(e.first.value, 'a');
+    });
+
+    test("last", () {
+      var e = enumerate(['a', 'b', 'c']);
+      expect(e.last.value, 'c');
+      expect(e.last.index, 2);
+      expect(e.last.value, 'c');
+    });
+
+    test("single", () {
+      var e = enumerate(['a']);
+      expect(e.single.value, 'a');
+      expect(e.single.index, 0);
+      expect(e.single.value, 'a');
+
+      expect(() => enumerate([1, 2]).single, throws);
+    });
+
+    test("length", () {
+      expect(enumerate([7, 8, 9]).length, 3);
+    });
+
+    test("elementAt", () {
+      var list = ['a', 'b', 'c'];
+      var e = enumerate(list);
+      for (int i = 2; i >= 0; i--) {
+        expect(e.elementAt(i).value, list[i]);
+        expect(e.elementAt(i).index, i);
+      }
+    });
+
+    test("equals and hashcode", () {
+      var list = ['a', 'b', 'c'];
+      var e1 = enumerate(list);
+      var e2 = enumerate(list);
+      for (int i = 0; i < 2; i++) {
+        expect(e1.elementAt(i), e2.elementAt(i));
+        expect(e1.elementAt(i).hashCode, e1.elementAt(i).hashCode);
+        expect(identical(e1.elementAt(i), e2.elementAt(i)), isFalse);
+      }
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/generating_iterable_test.dart b/packages/quiver_iterables/test/generating_iterable_test.dart
new file mode 100644
index 0000000..34b8f69
--- /dev/null
+++ b/packages/quiver_iterables/test/generating_iterable_test.dart
@@ -0,0 +1,43 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.property_iterable_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('GeneratingIterable', () {
+    test("should create an empty iterable for a null start object", () {
+      var iterable = new GeneratingIterable(() => null, (n) => null);
+      expect(iterable, []);
+    });
+
+    test("should create one-item empty iterable when next returns null", () {
+      var iterable = new GeneratingIterable(() => "Hello", (n) => null);
+      expect(iterable, ["Hello"]);
+    });
+
+    test("should add items until next returns null", () {
+      var parent = new Node();
+      var node = new Node()..parent = parent;
+      var iterable = new GeneratingIterable<Node>(() => node, (n) => n.parent);
+      expect(iterable, [node, parent]);
+    });
+  });
+}
+
+class Node {
+  Node parent;
+}
diff --git a/packages/quiver_iterables/test/merge_test.dart b/packages/quiver_iterables/test/merge_test.dart
new file mode 100644
index 0000000..793cd6e
--- /dev/null
+++ b/packages/quiver_iterables/test/merge_test.dart
@@ -0,0 +1,107 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.merge_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('merge', () {
+    test("should merge no iterables into empty iterable", () {
+      expect(merge([]), []);
+    });
+
+    test("should merge empty iterables into empty iterable", () {
+      expect(merge([[]]), []);
+      expect(merge([[], []]), []);
+      expect(merge([[], [], []]), []);
+      for (int i = 4; i <= 10; i++) {
+        expect(merge(new List.filled(i, const [])), []);
+      }
+    });
+
+    test("should merge single-element iterables", () {
+      expect(
+          merge([
+            ['a'],
+            ['b']
+          ]),
+          ['a', 'b']);
+    });
+
+    test("should output the union of elements in both iterables", () {
+      var a = ['a', 'b', 'c'];
+      expect(merge([a, a]), ['a', 'a', 'b', 'b', 'c', 'c']);
+    });
+
+    test("should honor the comparator", () {
+      var a = ['c', 'b', 'a'];
+      expect(merge([a, a], (x, y) => -x.compareTo(y)),
+          ['c', 'c', 'b', 'b', 'a', 'a']);
+    });
+
+    test("should merge empty iterables with non-empty ones", () {
+      var a = ['a', 'b', 'c'];
+      expect(merge([a, []]), ['a', 'b', 'c']);
+      expect(merge([[], a]), ['a', 'b', 'c']);
+    });
+
+    test("should throw on null elements", () {
+      var a = ['a', null, 'c'];
+      var b = ['a', 'b', 'c'];
+      expect(() => merge([a, b]).forEach((e) {}), throws);
+      expect(() => merge([b, a]).forEach((e) {}), throws);
+    });
+
+    test("should handle zig-zag case", () {
+      var a = ['a', 'a', 'd', 'f'];
+      var b = ['b', 'c', 'g', 'g'];
+      expect(merge([a, b]), ['a', 'a', 'b', 'c', 'd', 'f', 'g', 'g']);
+    });
+
+    test("should handle max(a) < min(b) case", () {
+      var a = <String>['a', 'b'];
+      var b = <String>['c', 'd'];
+      expect(max(a).compareTo(min(b)) < 0, isTrue); // test the test
+      expect(merge([a, b]), ['a', 'b', 'c', 'd']);
+    });
+
+    test("should handle three-way zig-zag case", () {
+      var a = ['a', 'd', 'g', 'j'];
+      var b = ['b', 'e', 'h', 'k'];
+      var c = ['c', 'f', 'i', 'l'];
+      var expected = [
+        'a',
+        'b',
+        'c',
+        'd',
+        'e',
+        'f',
+        'g',
+        'h',
+        'i',
+        'j',
+        'k',
+        'l'
+      ];
+      expect(merge([a, b, c]), expected);
+      expect(merge([a, c, b]), expected);
+      expect(merge([b, a, c]), expected);
+      expect(merge([b, c, a]), expected);
+      expect(merge([c, a, b]), expected);
+      expect(merge([c, b, a]), expected);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/min_max_test.dart b/packages/quiver_iterables/test/min_max_test.dart
new file mode 100644
index 0000000..aeb0edd
--- /dev/null
+++ b/packages/quiver_iterables/test/min_max_test.dart
@@ -0,0 +1,60 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.min_max_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('max', () {
+    test('should return the maximum element', () {
+      expect(max([2, 5, 1, 4]), 5);
+    });
+
+    test('should return null if the iterable is empty', () {
+      expect(max([]), null);
+    });
+  });
+
+  group('min', () {
+    test('should return the minimum element', () {
+      expect(min([2, 5, 1, 4]), 1);
+    });
+
+    test('should return null if the iterable is empty', () {
+      expect(min([]), null);
+    });
+  });
+
+  group('extent', () {
+    test('should return the max and min elements', () {
+      var ext = extent([2, 5, 1, 4]);
+      expect(ext.min, 1);
+      expect(ext.max, 5);
+    });
+
+    test('should return the single element', () {
+      var ext = extent([2]);
+      expect(ext.min, 2);
+      expect(ext.max, 2);
+    });
+
+    test('should return null if the iterable is empty', () {
+      var ext = extent([]);
+      expect(ext.min, null);
+      expect(ext.max, null);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/partition_test.dart b/packages/quiver_iterables/test/partition_test.dart
new file mode 100644
index 0000000..088b150
--- /dev/null
+++ b/packages/quiver_iterables/test/partition_test.dart
@@ -0,0 +1,59 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.partition_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('partition', () {
+    test('should throw when size is <= 0', () {
+      expect(() => partition([1, 2, 3], 0), throwsArgumentError);
+      expect(() => partition([1, 2, 3], -1), throwsArgumentError);
+    });
+
+    test('should return an empty list for empty input iterable', () {
+      expect(partition([], 5), equals([]));
+    });
+
+    test('should return one partition if partition size < input size', () {
+      var it = partition([1, 2, 3], 5).iterator;
+      expect(it.moveNext(), isTrue);
+      expect(it.current, equals([1, 2, 3]));
+      expect(it.moveNext(), isFalse);
+      expect(it.current, isNull);
+    });
+
+    test('should return one partition if partition size == input size', () {
+      var it = partition([1, 2, 3, 4, 5], 5).iterator;
+      expect(it.moveNext(), isTrue);
+      expect(it.current, equals([1, 2, 3, 4, 5]));
+      expect(it.moveNext(), isFalse);
+      expect(it.current, isNull);
+    });
+
+    test(
+        'should return partitions of correct size if '
+        'partition size > input size', () {
+      var it = partition([1, 2, 3, 4, 5], 3).iterator;
+      expect(it.moveNext(), isTrue);
+      expect(it.current, equals([1, 2, 3]));
+      expect(it.moveNext(), isTrue);
+      expect(it.current, equals([4, 5]));
+      expect(it.moveNext(), isFalse);
+      expect(it.current, isNull);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/range_test.dart b/packages/quiver_iterables/test/range_test.dart
new file mode 100644
index 0000000..f181a26
--- /dev/null
+++ b/packages/quiver_iterables/test/range_test.dart
@@ -0,0 +1,57 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.range_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('range', () {
+    test("should create an empty iterator if stop is 0", () {
+      expect(range(0), []);
+    });
+
+    test("should create a sequence from 0 to stop - 1", () {
+      expect(range(10), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+    });
+
+    test("should start sequences at start_or_stop", () {
+      expect(range(1, 11), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    });
+
+    test("should create an empty iterator if start and stop are equal", () {
+      expect(range(1, 1), []);
+    });
+
+    test("should step by step", () {
+      expect(range(0, 10, 2), [0, 2, 4, 6, 8]);
+      expect(range(0, 10, 3), [0, 3, 6, 9]);
+    });
+
+    test("should step by a negative step", () {
+      expect(range(10, 0, -1), [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
+      expect(range(0, -8, -1), [0, -1, -2, -3, -4, -5, -6, -7]);
+      expect(range(0, -10, -3), [0, -3, -6, -9]);
+    });
+
+    test("should throw with a bad range", () {
+      expect(() => range(10, 0), throws);
+    });
+
+    test("should throw with a bad step", () {
+      expect(() => range(0, 10, -1), throws);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/test/zip_test.dart b/packages/quiver_iterables/test/zip_test.dart
new file mode 100644
index 0000000..4a3bcd6
--- /dev/null
+++ b/packages/quiver_iterables/test/zip_test.dart
@@ -0,0 +1,63 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+library quiver.iterables.zip_test;
+
+import 'package:test/test.dart';
+import 'package:quiver_iterables/iterables.dart';
+
+main() {
+  group('zip', () {
+    test("should create an empty iterable if given no iterables", () {
+      expect(zip([]), []);
+    });
+
+    test("should zip equal length lists", () {
+      expect(
+          zip([
+            [1, 2, 3],
+            ['a', 'b', 'c']
+          ]),
+          [
+        [1, 'a'],
+        [2, 'b'],
+        [3, 'c']
+      ]);
+      expect(
+          zip([
+            [1, 2],
+            ['a', 'b'],
+            [2, 4]
+          ]),
+          [
+        [1, 'a', 2],
+        [2, 'b', 4]
+      ]);
+    });
+
+    test("should stop at the end of the shortest iterable", () {
+      expect(
+          zip([
+            [1, 2],
+            ['a', 'b'],
+            []
+          ]),
+          []);
+      expect(zip([range(2), range(4)]), [
+        [0, 0],
+        [1, 1]
+      ]);
+    });
+  });
+}
diff --git a/packages/quiver_iterables/tool/travis.sh b/packages/quiver_iterables/tool/travis.sh
new file mode 100755
index 0000000..61c101b
--- /dev/null
+++ b/packages/quiver_iterables/tool/travis.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (c) 2015, Google Inc. 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.
+
+# Fast fail the script on failures.
+set -e
+
+# Verify that the libraries are error and warning-free.
+echo "Running dartanalyzer..."
+libs=$(find lib -maxdepth 1 -type f -name '*.dart')
+dartanalyzer $DARTANALYZER_FLAGS $libs test/all_tests.dart
+
+# Run the tests.
+echo "Running tests..."
+pub run test:test
+
+# Gather and send coverage data.
+if [ "$REPO_TOKEN" ] && [ "$TRAVIS_DART_VERSION" = "stable" ]; then
+  echo "Collecting coverage..."
+  pub global activate dart_coveralls
+  pub global run dart_coveralls report \
+    --token $REPO_TOKEN \
+    --retry 2 \
+    --exclude-test-files \
+    test/all_tests.dart
+fi