Initial hack at partials support.
diff --git a/lib/mustache.dart b/lib/mustache.dart
index ff98e45..818f4b2 100644
--- a/lib/mustache.dart
+++ b/lib/mustache.dart
@@ -5,6 +5,7 @@
 part 'char_reader.dart';
 part 'scanner.dart';
 part 'template.dart';
+part 'mustache_context.dart';
 
 /// [Mustache template documentation](http://mustache.github.com/mustache.5.html)
 
@@ -18,6 +19,7 @@
 
 /// A Template can be rendered multiple times with different values.
 abstract class Template {
+  
 	/// [values] can be a combination of Map, List, String. Any non-String object
 	/// will be converted using toString(). Null values will cause a 
 	/// FormatException, unless lenient module is enabled.
@@ -43,3 +45,19 @@
 	MustacheFormatException(this.message, this.line, this.column);
 	String toString() => message;
 }
+
+//TODO does this require some sort of context to find partials nested in subdirs?
+typedef Template PartialResolver(String templateName);
+
+// Required for handing partials
+abstract class MustacheContext {
+
+  factory MustacheContext(PartialResolver partialResolver,
+      {bool lenient, bool htmlEscapeValues}) = _MustacheContext;
+  
+  String renderString(String templateName, values);
+  
+  void render(String templateName, values, StringSink sink);
+}
+
+
diff --git a/lib/mustache_context.dart b/lib/mustache_context.dart
new file mode 100644
index 0000000..9a722d3
--- /dev/null
+++ b/lib/mustache_context.dart
@@ -0,0 +1,27 @@
+part of mustache;
+
+class _MustacheContext implements MustacheContext {
+
+  _MustacheContext(PartialResolver partialResolver,
+      {bool lenient: false, bool htmlEscapeValues: true})
+      : _partialResolver = partialResolver,
+        _lenient = lenient,
+        _htmlEscapeValues = htmlEscapeValues;
+  
+  final PartialResolver _partialResolver;
+  final bool _lenient;
+  final bool _htmlEscapeValues;
+  
+  String renderString(String templateName, values) {
+    var template = _partialResolver(templateName);
+    return template.renderString(values, 
+        lenient: _lenient, htmlEscapeValues: _htmlEscapeValues);
+  }
+  
+  void render(String templateName, values, StringSink sink) {
+    var template = _partialResolver(templateName);
+    template.render(values, sink, 
+        lenient: _lenient, htmlEscapeValues: _htmlEscapeValues);    
+  }
+  
+}
diff --git a/lib/template.dart b/lib/template.dart
index 3df8302..29a71ff 100644
--- a/lib/template.dart
+++ b/lib/template.dart
@@ -14,9 +14,9 @@
 _Node _parseTokens(List<_Token> tokens, bool lenient) {

 	var stack = new List<_Node>()..add(new _Node(_OPEN_SECTION, 'root', 0, 0));

 	for (var t in tokens) {

-		if (t.type == _TEXT || t.type == _VARIABLE || t.type == _UNESC_VARIABLE) {

+		if (const [_TEXT, _VARIABLE, _UNESC_VARIABLE, _PARTIAL].contains(t.type)) {

 			if (t.type == _VARIABLE || t.type == _UNESC_VARIABLE)

-			_checkTagChars(t, lenient);

+			  _checkTagChars(t, lenient);

 			stack.last.children.add(new _Node.fromToken(t));

 

 		} else if (t.type == _OPEN_SECTION || t.type == _OPEN_INV_SECTION) {

@@ -58,7 +58,9 @@
 }

 

 class _Template implements Template {

-	_Template(this._root, this._lenient) {

+  

+	_Template(this._root, this._lenient)

+	{

 		_htmlEscapeMap[_AMP] = '&amp;';

 		_htmlEscapeMap[_LT] = '&lt;';

 		_htmlEscapeMap[_GT] = '&gt;';

@@ -68,9 +70,18 @@
 	}

 

 	final _Node _root;

+	

+	//FIXME careful there is a potential concurrency bug as _stack is mutated 

+	// during rendering, and if async lazy loading of partials is added this

+	// could be mutated by multiple async calls to render running concurrently.

+	// Perhaps pass this around as an argument, or create a render context object.

+	// Same is true with sink.

 	final List _stack = new List();

 	final Map _htmlEscapeMap = new Map<int, String>();

 	final bool _lenient;

+	

+	//FIXME quick ugly hack.

+	PartialResolver partialResolver;

 

 	bool _htmlEscapeValues;

 	StringSink _sink;

@@ -90,6 +101,17 @@
 		_sink = null;

 	}

 

+	//TODO Share code with render.

+  void _renderWithStack(List stack, StringSink sink,

+                        {bool lenient : false, bool htmlEscapeValues : true}) {

+    _sink = sink;

+    _htmlEscapeValues = htmlEscapeValues;

+    _stack.clear();

+    _stack.addAll(stack);

+    _root.children.forEach(_renderNode);

+    _sink = null;

+  }

+	

 	_write(String output) => _sink.write(output);

 

 	_renderNode(node) {

@@ -109,6 +131,9 @@
 			case _OPEN_INV_SECTION:

 				_renderInvSection(node);

 				break;

+			case _PARTIAL:

+			  _renderPartial(node);

+			  break;

 			case _COMMENT:

 				break; // Do nothing.

 			default:

@@ -251,6 +276,12 @@
 		}

 	}

 

+  _renderPartial(_Node node) {

+    var partialName = node.value;

+    _Template template = partialResolver(partialName);

+    template._renderWithStack(_stack, _sink);

+  }

+

 	String _htmlEscape(String s) {

 		var buffer = new StringBuffer();

 		int startIndex = 0;

diff --git a/test/mustache_test.dart b/test/mustache_test.dart
index bb020eb..30fd6b7 100644
--- a/test/mustache_test.dart
+++ b/test/mustache_test.dart
@@ -234,11 +234,23 @@
 		});
 	});
 
-	group('Patial tag', () {
-		test('Unimplemented', () {
-			var fn = () => parse('{{>partial}}').renderString({});
-			expect(fn, throwsUnimplementedError);
-		});
+	solo_group('Partial tag', () {
+		
+		test('MustacheContext', () {
+		  var template = parse('{{>partial}}'); 
+		  var includedTemplate = parse('{{foo}}');
+		  var resolver = (name) => 
+		      {'root': template, 'partial': includedTemplate}[name];
+		      
+		  //FIXME Need a sensible way to initialise the resolver.
+		  template.partialResolver = resolver;
+		  includedTemplate.partialResolver = resolver; 
+		  
+		  var ctx = new MustacheContext(resolver);
+		  var output = ctx.renderString('root', {'foo': 'bar'});
+		  expect(output, 'bar');
+    });
+        
 	});
 
 	group('Other', () {