Add travis support and dartfmt... (#6)

* Add travis support for pkg/convert.

* Run dartfmt.

* Only dartfmt stable.

* Remove --platform chrome.
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..10d307b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: dart
+sudo: false
+dart:
+  - dev
+  - stable
+cache:
+  directories:
+    - $HOME/.pub-cache
+dart_task:
+  - test: --platform vm
+  - test: --platform dartium
+    install_dartium: true
+  - dartanalyzer
+  - dartfmt
+matrix:
+  exclude:
+    - dart: dev
+      dart_task: dartfmt
diff --git a/lib/src/hex/decoder.dart b/lib/src/hex/decoder.dart
index d7a7555..c1c8feb 100644
--- a/lib/src/hex/decoder.dart
+++ b/lib/src/hex/decoder.dart
@@ -22,8 +22,8 @@
 
   List<int> convert(String string) {
     if (!string.length.isEven) {
-      throw new FormatException("Invalid input length, must be even.",
-          string, string.length);
+      throw new FormatException(
+          "Invalid input length, must be even.", string, string.length);
     }
 
     var bytes = new Uint8List(string.length ~/ 2);
diff --git a/lib/src/hex/encoder.dart b/lib/src/hex/encoder.dart
index a9c66a5..9339cda 100644
--- a/lib/src/hex/encoder.dart
+++ b/lib/src/hex/encoder.dart
@@ -77,7 +77,8 @@
     if (byte >= 0 && byte <= 0xff) continue;
     throw new FormatException(
         "Invalid byte ${byte < 0 ? "-" : ""}0x${byte.abs().toRadixString(16)}.",
-        bytes, i);
+        bytes,
+        i);
   }
 
   throw 'unreachable';
diff --git a/lib/src/percent/decoder.dart b/lib/src/percent/decoder.dart
index 4d8f994..334e754 100644
--- a/lib/src/percent/decoder.dart
+++ b/lib/src/percent/decoder.dart
@@ -34,8 +34,7 @@
 
     if (lastDigit != null) {
       throw new FormatException(
-          "Input ended with incomplete encoded byte.",
-          string, string.length);
+          "Input ended with incomplete encoded byte.", string, string.length);
     }
 
     return buffer.buffer.asUint8List(0, buffer.length);
@@ -229,8 +228,8 @@
   return null;
 }
 
-void _checkForInvalidCodeUnit(int codeUnitOr, List<int> codeUnits, int start,
-    int end) {
+void _checkForInvalidCodeUnit(
+    int codeUnitOr, List<int> codeUnits, int start, int end) {
   if (codeUnitOr >= 0 && codeUnitOr <= 0x7f) return;
 
   for (var i = start; i < end; i++) {
@@ -238,7 +237,8 @@
     if (codeUnit >= 0 && codeUnit <= 0x7f) continue;
     throw new FormatException(
         "Non-ASCII code unit "
-            "U+${codeUnit.toRadixString(16).padLeft(4, '0')}",
-        codeUnits, i);
+        "U+${codeUnit.toRadixString(16).padLeft(4, '0')}",
+        codeUnits,
+        i);
   }
 }
diff --git a/lib/src/percent/encoder.dart b/lib/src/percent/encoder.dart
index 790caff..d4419a9 100644
--- a/lib/src/percent/encoder.dart
+++ b/lib/src/percent/encoder.dart
@@ -94,7 +94,8 @@
     if (byte >= 0 && byte <= 0xff) continue;
     throw new FormatException(
         "Invalid byte ${byte < 0 ? "-" : ""}0x${byte.abs().toRadixString(16)}.",
-        bytes, i);
+        bytes,
+        i);
   }
 
   throw 'unreachable';
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 6bd4468..7990779 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -33,7 +33,7 @@
 
   throw new FormatException(
       "Invalid hexadecimal code unit "
-          "U+${codeUnit.toRadixString(16).padLeft(4, '0')}.",
-      codeUnits, index);
+      "U+${codeUnit.toRadixString(16).padLeft(4, '0')}.",
+      codeUnits,
+      index);
 }
-
diff --git a/test/hex_test.dart b/test/hex_test.dart
index 837085f..95f0e90 100644
--- a/test/hex_test.dart
+++ b/test/hex_test.dart
@@ -48,8 +48,8 @@
     test("rejects non-bytes", () {
       expect(() => hex.encode([0x100]), throwsFormatException);
 
-      var sink = hex.encoder.startChunkedConversion(
-          new StreamController(sync: true));
+      var sink =
+          hex.encoder.startChunkedConversion(new StreamController(sync: true));
       expect(() => sink.add([0x100]), throwsFormatException);
     });
   });
@@ -61,9 +61,21 @@
     });
 
     test("supports uppercase letters", () {
-      expect(hex.decode("0123456789ABCDEFabcdef"), equals([
-        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef
-      ]));
+      expect(
+          hex.decode("0123456789ABCDEFabcdef"),
+          equals([
+            0x01,
+            0x23,
+            0x45,
+            0x67,
+            0x89,
+            0xab,
+            0xcd,
+            0xef,
+            0xab,
+            0xcd,
+            0xef
+          ]));
     });
 
     group("with chunked conversion", () {
@@ -78,26 +90,55 @@
 
       test("converts hex to byte arrays", () {
         sink.add("1ab23cd4");
-        expect(results, equals([[0x1a, 0xb2, 0x3c, 0xd4]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2, 0x3c, 0xd4]
+            ]));
 
         sink.add("0001feff");
-        expect(results,
-            equals([[0x1a, 0xb2, 0x3c, 0xd4], [0x00, 0x01, 0xfe, 0xff]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2, 0x3c, 0xd4],
+              [0x00, 0x01, 0xfe, 0xff]
+            ]));
       });
 
       test("supports trailing digits split across chunks", () {
         sink.add("1ab23");
-        expect(results, equals([[0x1a, 0xb2]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2]
+            ]));
 
         sink.add("cd");
-        expect(results, equals([[0x1a, 0xb2], [0x3c]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2],
+              [0x3c]
+            ]));
 
         sink.add("40001");
-        expect(results, equals([[0x1a, 0xb2], [0x3c], [0xd4, 0x00, 0x01]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2],
+              [0x3c],
+              [0xd4, 0x00, 0x01]
+            ]));
 
         sink.add("feff");
-        expect(results,
-            equals([[0x1a, 0xb2], [0x3c], [0xd4, 0x00, 0x01], [0xfe, 0xff]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2],
+              [0x3c],
+              [0xd4, 0x00, 0x01],
+              [0xfe, 0xff]
+            ]));
       });
 
       test("supports empty strings", () {
@@ -111,36 +152,63 @@
         expect(results, equals([[]]));
 
         sink.add("0");
-        expect(results, equals([[], [0x00]]));
+        expect(
+            results,
+            equals([
+              [],
+              [0x00]
+            ]));
 
         sink.add("");
-        expect(results, equals([[], [0x00]]));
+        expect(
+            results,
+            equals([
+              [],
+              [0x00]
+            ]));
       });
 
       test("rejects odd length detected in close()", () {
         sink.add("1ab23");
-        expect(results, equals([[0x1a, 0xb2]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2]
+            ]));
         expect(() => sink.close(), throwsFormatException);
       });
 
       test("rejects odd length detected in addSlice()", () {
         sink.addSlice("1ab23cd", 0, 5, false);
-        expect(results, equals([[0x1a, 0xb2]]));
+        expect(
+            results,
+            equals([
+              [0x1a, 0xb2]
+            ]));
 
-        expect(() => sink.addSlice("1ab23cd", 5, 7, true),
-            throwsFormatException);
+        expect(
+            () => sink.addSlice("1ab23cd", 5, 7, true), throwsFormatException);
       });
     });
 
     group("rejects non-hex character", () {
-      for (var char in
-             ["g", "G", "/", ":", "@", "`", "\x00", "\u0141", "\u{10041}"]) {
+      for (var char in [
+        "g",
+        "G",
+        "/",
+        ":",
+        "@",
+        "`",
+        "\x00",
+        "\u0141",
+        "\u{10041}"
+      ]) {
         test('"$char"', () {
           expect(() => hex.decode("a$char"), throwsFormatException);
           expect(() => hex.decode("${char}a"), throwsFormatException);
 
-          var sink = hex.decoder.startChunkedConversion(
-              new StreamController(sync: true));
+          var sink = hex.decoder
+              .startChunkedConversion(new StreamController(sync: true));
           expect(() => sink.add(char), throwsFormatException);
         });
       }
diff --git a/test/percent_test.dart b/test/percent_test.dart
index a4a6fb7..c2f0a3c 100644
--- a/test/percent_test.dart
+++ b/test/percent_test.dart
@@ -11,19 +11,96 @@
 void main() {
   group("encoder", () {
     test("doesn't percent-encode unreserved characters", () {
-      expect(percent.encode([
-        $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, $q, $r,
-        $s, $t, $u, $v, $w, $x, $y, $z, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J,
-        $K, $L, $M, $N, $O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, $0, $1,
-        $2, $3, $4, $5, $6, $7, $8, $9, $dash, $dot, $underscore, $tilde
-      ]), equals("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"));
+      expect(
+          percent.encode([
+            $a,
+            $b,
+            $c,
+            $d,
+            $e,
+            $f,
+            $g,
+            $h,
+            $i,
+            $j,
+            $k,
+            $l,
+            $m,
+            $n,
+            $o,
+            $p,
+            $q,
+            $r,
+            $s,
+            $t,
+            $u,
+            $v,
+            $w,
+            $x,
+            $y,
+            $z,
+            $A,
+            $B,
+            $C,
+            $D,
+            $E,
+            $F,
+            $G,
+            $H,
+            $I,
+            $J,
+            $K,
+            $L,
+            $M,
+            $N,
+            $O,
+            $P,
+            $Q,
+            $R,
+            $S,
+            $T,
+            $U,
+            $V,
+            $W,
+            $X,
+            $Y,
+            $Z,
+            $0,
+            $1,
+            $2,
+            $3,
+            $4,
+            $5,
+            $6,
+            $7,
+            $8,
+            $9,
+            $dash,
+            $dot,
+            $underscore,
+            $tilde
+          ]),
+          equals(
+              "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~"));
     });
 
     test("percent-encodes reserved ASCII characters", () {
-      expect(percent.encode([
-        $space, $backquote, $open_brace, $at, $open_bracket, $comma,
-        $division, $caret, $close_brace, $del, $nul, $percent
-      ]), equals("%20%60%7B%40%5B%2C%2F%5E%7D%7F%00%25"));
+      expect(
+          percent.encode([
+            $space,
+            $backquote,
+            $open_brace,
+            $at,
+            $open_bracket,
+            $comma,
+            $division,
+            $caret,
+            $close_brace,
+            $del,
+            $nul,
+            $percent
+          ]),
+          equals("%20%60%7B%40%5B%2C%2F%5E%7D%7F%00%25"));
     });
 
     test("percent-encodes non-ASCII characters", () {
@@ -31,8 +108,8 @@
     });
 
     test("mixes encoded and unencoded characters", () {
-      expect(percent.encode([$a, $plus, $b, $equal, 0x80]),
-          equals("a%2Bb%3D%80"));
+      expect(
+          percent.encode([$a, $plus, $b, $equal, 0x80]), equals("a%2Bb%3D%80"));
     });
 
     group("with chunked conversion", () {
@@ -69,8 +146,8 @@
     test("rejects non-bytes", () {
       expect(() => percent.encode([0x100]), throwsFormatException);
 
-      var sink = percent.encoder.startChunkedConversion(
-          new StreamController(sync: true));
+      var sink = percent.encoder
+          .startChunkedConversion(new StreamController(sync: true));
       expect(() => sink.add([0x100]), throwsFormatException);
     });
   });
@@ -82,8 +159,8 @@
     });
 
     test("supports lowercase letters", () {
-      expect(percent.decode("a%2bb%3d%80"),
-          equals([$a, $plus, $b, $equal, 0x80]));
+      expect(
+          percent.decode("a%2bb%3d%80"), equals([$a, $plus, $b, $equal, 0x80]));
     });
 
     test("supports more aggressive encoding", () {
@@ -91,10 +168,21 @@
     });
 
     test("supports less aggressive encoding", () {
-      expect(percent.decode(" `{@[,/^}\x7F\x00"), equals([
-        $space, $backquote, $open_brace, $at, $open_bracket, $comma,
-        $division, $caret, $close_brace, $del, $nul
-      ]));
+      expect(
+          percent.decode(" `{@[,/^}\x7F\x00"),
+          equals([
+            $space,
+            $backquote,
+            $open_brace,
+            $at,
+            $open_bracket,
+            $comma,
+            $division,
+            $caret,
+            $close_brace,
+            $del,
+            $nul
+          ]));
     });
 
     group("with chunked conversion", () {
@@ -109,25 +197,52 @@
 
       test("converts percent to byte arrays", () {
         sink.add("a%2Bb%3D%801");
-        expect(results, equals([[$a, $plus, $b, $equal, 0x80, $1]]));
+        expect(
+            results,
+            equals([
+              [$a, $plus, $b, $equal, 0x80, $1]
+            ]));
 
         sink.add("%00%01%FE%FF");
-        expect(results,
-            equals([[$a, $plus, $b, $equal, 0x80, $1], [0x00, 0x01, 0xfe, 0xff]]));
+        expect(
+            results,
+            equals([
+              [$a, $plus, $b, $equal, 0x80, $1],
+              [0x00, 0x01, 0xfe, 0xff]
+            ]));
       });
 
       test("supports trailing percents and digits split across chunks", () {
         sink.add("ab%");
-        expect(results, equals([[$a, $b]]));
+        expect(
+            results,
+            equals([
+              [$a, $b]
+            ]));
 
         sink.add("2");
-        expect(results, equals([[$a, $b]]));
+        expect(
+            results,
+            equals([
+              [$a, $b]
+            ]));
 
         sink.add("0cd%2");
-        expect(results, equals([[$a, $b], [$space, $c, $d]]));
+        expect(
+            results,
+            equals([
+              [$a, $b],
+              [$space, $c, $d]
+            ]));
 
         sink.add("0");
-        expect(results, equals(([[$a, $b], [$space, $c, $d], [$space]])));
+        expect(
+            results,
+            equals(([
+              [$a, $b],
+              [$space, $c, $d],
+              [$space]
+            ])));
       });
 
       test("supports empty strings", () {
@@ -147,35 +262,54 @@
         expect(results, equals([[]]));
 
         sink.add("0");
-        expect(results, equals([[], [0x20]]));
+        expect(
+            results,
+            equals([
+              [],
+              [0x20]
+            ]));
       });
 
       test("rejects dangling % detected in close()", () {
         sink.add("ab%");
-        expect(results, equals([[$a, $b]]));
+        expect(
+            results,
+            equals([
+              [$a, $b]
+            ]));
         expect(() => sink.close(), throwsFormatException);
       });
 
       test("rejects dangling digit detected in close()", () {
         sink.add("ab%2");
-        expect(results, equals([[$a, $b]]));
+        expect(
+            results,
+            equals([
+              [$a, $b]
+            ]));
         expect(() => sink.close(), throwsFormatException);
       });
 
       test("rejects danging % detected in addSlice()", () {
         sink.addSlice("ab%", 0, 3, false);
-        expect(results, equals([[$a, $b]]));
+        expect(
+            results,
+            equals([
+              [$a, $b]
+            ]));
 
-        expect(() => sink.addSlice("ab%", 0, 3, true),
-            throwsFormatException);
+        expect(() => sink.addSlice("ab%", 0, 3, true), throwsFormatException);
       });
 
       test("rejects danging digit detected in addSlice()", () {
         sink.addSlice("ab%2", 0, 3, false);
-        expect(results, equals([[$a, $b]]));
+        expect(
+            results,
+            equals([
+              [$a, $b]
+            ]));
 
-        expect(() => sink.addSlice("ab%2", 0, 3, true),
-            throwsFormatException);
+        expect(() => sink.addSlice("ab%2", 0, 3, true), throwsFormatException);
       });
     });
 
@@ -185,8 +319,8 @@
           expect(() => percent.decode("a$char"), throwsFormatException);
           expect(() => percent.decode("${char}a"), throwsFormatException);
 
-          var sink = percent.decoder.startChunkedConversion(
-              new StreamController(sync: true));
+          var sink = percent.decoder
+              .startChunkedConversion(new StreamController(sync: true));
           expect(() => sink.add(char), throwsFormatException);
         });
       }