Initial implementation.
diff --git a/lib/resource.dart b/lib/resource.dart
new file mode 100644
index 0000000..dbed97a
--- /dev/null
+++ b/lib/resource.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file

+// for details. All rights reserved. Use of this source code is governed by a

+// BSD-style license that can be found in the LICENSE file.

+

+/// A [Resource] is data that can be loaded into a Dart program.

+///

+/// This library provides an implementation of [Resource] and a

+/// [PackageResolver] that controls how package: URIs are converted to

+/// URIs that can be loaded.

+library resource;

+

+export "src/resource.dart" show Resource, PackageResolver;

diff --git a/lib/src/io.dart b/lib/src/io.dart
new file mode 100644
index 0000000..8237c01
--- /dev/null
+++ b/lib/src/io.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file

+// for details. All rights reserved. Use of this source code is governed by a

+// BSD-style license that can be found in the LICENSE file.

+

+// dart:io based strategy for loading resources.

+

+import "dart:io" show File, HttpClient, HttpClientRequest, HttpClientResponse;

+import "dart:async" show Future, Stream;

+import "dart:convert" show Encoding, UTF8;

+import "package:typed_data/typed_buffers.dart" show Uint8Buffer;

+

+Stream<List<int>> readAsStream(Uri uri) async* {

+  if (uri.scheme == "file") {

+    yield* new File.fromUri(uri).openRead();

+    return;

+  }

+  if (uri.scheme == "http" || uri.scheme == "https") {

+    HttpClientResponse response = await _httpGet(uri);

+    yield* response;

+    return;

+  }

+  throw new UnsupportedError("Unsupported scheme: $uri");

+}

+

+Future<List<int>> readAsBytes(Uri uri) async {

+  if (uri.scheme == "file") {

+    return new File.fromUri(uri).readAsBytes();

+  }

+  if (uri.scheme == "http" || uri.scheme == "https") {

+    HttpClientResponse response = await _httpGet(uri);

+    Uint8Buffer buffer = new Uint8Buffer();

+    await for (var bytes in response) {

+      buffer.addAll(bytes);

+    }

+    return buffer.toList();

+  }

+  throw new UnsupportedError("Unsupported scheme: $uri");

+}

+

+Future<String> readAsString(Uri uri, Encoding encoding) async {

+  if (encoding == null) encoding = UTF8;

+  if (uri.scheme == "file") {

+    return new File.fromUri(uri).readAsString(encoding: encoding);

+  }

+  if (uri.scheme == "http" || uri.scheme == "https") {

+    HttpClientResponse response = await _httpGet(uri);

+    Uint8Buffer buffer = new Uint8Buffer();

+    await for (var bytes in response) {

+      buffer.addAll(bytes);

+    }

+    new String.fromCharCodes(buffer.toList());

+  }

+  throw new UnsupportedError("Unsupported scheme: $uri");

+}

+

+Future<HttpClientResponse> _httpGet(Uri uri) async {

+  HttpClientRequest request = await new HttpClient().getUrl(uri);

+  return await request.close();

+}

diff --git a/lib/src/resource.dart b/lib/src/resource.dart
new file mode 100644
index 0000000..2fef5f6
--- /dev/null
+++ b/lib/src/resource.dart
@@ -0,0 +1,218 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file

+// for details. All rights reserved. Use of this source code is governed by a

+// BSD-style license that can be found in the LICENSE file.

+

+library resoure.resource;

+

+import "dart:async" show Future, Stream;

+import "dart:convert" show Encoding;

+import "dart:isolate" show Isolate;

+import "package_resolver.dart";

+import "io.dart" as io;  // Loading strategy. TODO: Be configuration dependent.

+

+/// A strategy for resolving package URIs

+abstract class PackageResolver {

+  /// Cache of the current resolver, accessible directly after it has first

+  /// been found asynchronously.

+  static PackageResolver _current;

+

+  /// The package resolution strategy used by the current isolate.

+  static final Future<PackageResolver> current = _findIsolateResolution();

+

+  PackageResolver();

+

+  /// Creates a resolver using a map from package name to package location.

+  factory PackageResolver.fromMap(Map<String, Uri> packages) = MapResolver;

+

+  /// Creates a resolver using a package root.

+  factory PackageResolver.fromRoot(Uri packageRoot) = RootResolver;

+

+  /// Resolves a package URI to its location.

+  ///

+  /// If [uri] does not have `package` as scheme, it is returned again.

+  /// Otherwise the package name is looked up, and if found, a location

+  /// for the package file is returned.

+  Future<Uri> resolve(Uri uri);

+

+  /// Returns a [Resource] for the [uri] as resolved by this resolver.

+  Resource resource(Uri uri) {

+    return new _UriResource(this, uri);

+  }

+

+  /// Finds the way the current isolate resolves package URIs.

+  ///

+  /// Is only called once, and when it has been called, the [_current]

+  /// resolver is initialized, so [UriResource] will be initialized

+  /// with the resolver directly.

+  static Future<PackageResolver> _findIsolateResolution() async {

+    var pair = await Future.wait([Isolate.packageRoot, Isolate.packageMap]);

+    Uri root = pair[0];

+    if (root != null) {

+      _current = new RootResolver(root);

+    } else {

+      Map<String, Uri> map = pair[1];

+      _current = new MapResolver(map);

+    }

+    return _current;

+  }

+}

+

+/// A resource that can be read into the program.

+///

+/// A resource is data that can be located using a URI and read into

+/// the program at runtime.

+/// The URI may use the `package` scheme to read resources provided

+/// along with package sources.

+abstract class Resource {

+  /// Creates a resource object with the given [uri] as location.

+  ///

+  /// The `uri` is a string containing a valid URI.

+  /// If the string is not a valid URI, using any of the functions on

+  /// the resource object will fail.

+  ///

+  /// The URI may be relative, in which case it will be resolved

+  /// against [Uri.base] before being used.

+  ///

+  /// The URI may use the `package` scheme, which is always supported.

+  /// Other schemes may also be supported where possible.

+  const factory Resource(String uri) = _StringResource;

+

+  /// Creates a resource object with the given [uri] as location.

+  ///

+  /// The URI may be relative, in which case it will be resolved

+  /// against [Uri.base] before being used.

+  ///

+  /// The URI may use the `package` scheme, which is always supported.

+  /// Other schemes may also be supported where possible.

+  factory Resource.forUri(Uri uri) =>

+      new _UriResource(PackageResolver._current, uri);

+

+  /// The location `uri` of this resource.

+  ///

+  /// This is a [Uri] of the `uri` parameter given to the constructor.

+  /// If the parameter was not a valid URI, reading `uri` may fail.

+  Uri get uri;

+

+  Stream<List<int>> openRead();

+

+  Future<List<int>> readAsBytes();

+

+  /// Read the resource content as a string.

+  ///

+  /// The content is decoded into a string using an [Encoding].

+  /// If no other encoding is provided, it defaults to UTF-8.

+  Future<String> readAsString({Encoding encoding});

+}

+

+class _StringResource implements Resource {

+  final String _uri;

+

+  const _StringResource(String uri) : _uri = uri;

+

+  Uri get uri => Uri.parse(_uri);

+

+  Stream<List<int>> openRead() {

+    return new _UriResource(PackageResolver._current, uri).openRead();

+  }

+  Future<List<int>> readAsBytes() {

+    return new _UriResource(PackageResolver._current, uri).readAsBytes();

+  }

+  Future<String> readAsString({Encoding encoding}) {

+    return new _UriResource(PackageResolver._current, uri)

+                   .readAsString(encoding: encoding);

+  }

+}

+

+class _UriResource implements Resource {

+  /// The strategy for resolving package: URIs.

+  ///

+  /// May be null intially. If so, the [PackageResolver.current] resolver is

+  /// used (and cached for later use).

+  PackageResolver _resolver;

+

+  /// The URI of the resource.

+  final Uri uri;

+

+  _UriResource(this.resolver, Uri uri);

+

+  Stream<List<int>> openRead() async* {

+    Uri uri = await _resolve(this.uri);

+    return io.readAsStream(uri);

+  }

+

+  Future<List<int>> readAsBytes() async {

+    Uri uri = await _resolve(this.uri);

+    return io.readAsBytes(uri);

+  }

+

+  Future<String> readAsString({Encoding encoding}) async {

+    Uri uri = await _resolve(this.uri);

+    return io.readAsString(uri, encoding);

+  }

+

+  static void _checkPackageUri(Uri uri) {

+    if (uri.scheme != "package") {

+      throw new ArgumentError.value(uri, "Not a package: URI");

+    }

+    if (uri.hasAuthority) {

+      throw new ArgumentError.value(uri,

+          "A package: URI must not have an authority part");

+    }

+    if (uri.path.isEmpty || uri.path.startsWith('/')) {

+      throw new ArgumentError.value(uri,

+          "A package: URI must have the form "

+          "'package:packageName/packagePath'");

+    }

+    if (uri.hasQuery) {

+      throw new ArgumentError.value(uri,

+          "A package: URI must not have a query part");

+    }

+    if (uri.hasFragment) {

+      throw new ArgumentError.value(uri,

+          "A package: URI must not have a fragment part");

+    }

+  }

+

+  Future<Uri> _resolve(Uri uri) async {

+    if (uri.scheme != "package") {

+      return Uri.base.resolveUri(uri);

+    }

+    _checkPackageUri(uri);

+    _resolver ??= await PackageResolver._current;

+    return _resolver.resolve(uri);

+  }

+}

+

+/// A [PackageResolver] based on a packags map.

+class MapResolver extends PackageResolver {

+  Map<String, Uri> _mapping;

+

+  MapResolver(this._mapping);

+

+  Uri resolve(Uri uri) {

+    if (uri.scheme != "package") return uri;

+    var path = uri.path;

+    int slashIndex = path.indexOf('/');

+    if (slashIndex <= 0) {

+      throw new ArgumentError.value(uri, "Invalid package URI");

+    }

+    int packageName = path.substring(0, slashIndex);

+    var base = _mapping[packageName];

+    if (base != null) {

+      int packagePath = path.substring(slashIndex + 1);

+      return base.resolveUri(new Uri(path: packagePath));

+    }

+    throw new UnsupportedError("No package named '$packageName' found");

+  }

+}

+

+/// A [PackageResolver] based on a package root.

+class RootResolver extends PackageResolver {

+  Uri _root;

+  RootResolver(this._root);

+

+  Uri resolve(Uri uri) {

+    if (uri.scheme != "package") return uri;

+    return _root.resolve(uri.path);

+  }

+}

diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..6770e7f
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,7 @@
+name: resource

+version: 0.1.0

+dependencies:

+  http: "any"

+  typed_data: "any"

+dev_dependencies:

+  test: "any"