anchor.diff:          contents += ' ';
         }
       }
  -    return fence + contents + fence;
  -  }
  -
  -  String writeEmph(Emph emph, {String delimiter: "*"}) {
  -    return '${delimiter}${writeInlines(emph.contents, prevEmph: delimiter)}${delimiter}';
  -  }
  -
  -  String writeStrong(Strong strong, {String delimiter: "*"}) {
  +    write(fence);
  +    write(contents);
  +    write(fence);
  +  }
  +
  +  void writeEmph(Emph emph, {String delimiter: "*"}) {
  +    write(delimiter);
  +    writeInlines(emph.contents, prevEmph: delimiter);
  +    write(delimiter);
  +  }
  +
  +  void writeStrong(Strong strong, {String delimiter: "*"}) {
       String delimiterString = delimiter * 2;
  -    return '${delimiterString}${writeInlines(strong.contents, prevStrong: delimiter)}${delimiterString}';
  -  }
  -
  -  String writeLink(Link link) {
  -    String inlines = writeInlines(link.label);
  +    write(delimiterString);
  +    writeInlines(strong.contents);
  +    write(delimiterString);
  +  }
  +
  +  void writeLink(Link link) {
       if (link is InlineLink) {
  -      return '[${inlines}](${_writeTarget(link.target)})';
  -    }
  +      write('[');
  +      writeInlines(link.label);
  +      write('](');
  +      writeTarget(link.target);
  +      write(')');
  +      return;
  +    }
  +
       if (link is ReferenceLink) {
         _references[link.reference] = link.target;
  -      return '[${inlines}]' + (inlines.toUpperCase() != link.reference.toUpperCase() ? '[${link.reference}]' : '');
  +      _MarkdownBuilder builder = new _MarkdownBuilder(_references);
  +      builder.writeInlines(link.label);
  +      String inlines = builder.toString();
  +      write('[');
  +      write(inlines);
  +      write(']');
  +      if (inlines.toUpperCase() != link.reference.toUpperCase()) {
  +        write('[');
  +        write(link.reference);
  +        write(']');
  +      }
  +      return;
       }
   
       // Autolink
  +    write('<');
       if (link.label.length > 0 && link.label[0] is Str) {
  -      return '<' + link.label[0].contents + '>';
  -    }
  -    return '<' + link.target.link + '>';
  -  }
  -
  -  String writeImage(Image image) {
  -    return '![${writeInlines(image.label)}](${_writeTarget(image.target)})';
  -  }
  -
  -  String _writeReferences() {
  -    String result = "";
  +      write(link.label[0].contents);
  +    } else {
  +      write(link.target.link);
  +    }
  +    write('>');
  +  }
  +
  +  void writeImage(Image image) {
  +    // TODO reference images
  +    write('![');
  +    writeInlines(image.label);
  +    write('](');
  +    writeTarget(image.target);
  +    write(')');
  +  }
  +
  +  void writeTarget(Target target) {
  +    String result;
  +
  +    if (target.link.contains(' ') && !target.link.contains(r'[<>]')) {
  +      write('<' + target.link + '>');
  +    } else {
  +      write(escapeString(target.link));
  +    }
  +
  +    if (target.title != null) {
  +      write(' "${escapeString(target.title)}"');
  +    }
  +  }
  +
  +  void writeReferences() {
       _references.forEach((String ref, Target target) {
  -      result += '[$ref]: ${_writeTarget(target)}\n';
  +      write('[');
  +      write(ref);
  +      write(']: ');
  +      writeTarget(target);
  +      write('\n');
       });
  -
  -    return result;
  -  }
  -
  -  String _writeTarget(Target target) {
  -    String result;
  -
  -    if (target.link.contains(' ') && !target.link.contains(r'[<>]')) {
  -      result = '<' + target.link + '>';
  -    } else {
  -      result = escapeString(target.link);
  -    }
  -
  -    if (target.title != null) {
  -      result += ' "${escapeString(target.title)}"';
  -    }
  -    return result;
  -
  -  }
  -
  +  }
  +}
  +
  +
  +class MarkdownWriter {
  +  String write(Document document) {
  +    _MarkdownBuilder builder = new _MarkdownBuilder(<String, Target>{});
  +    builder.writeDocument(document);
  +
  +    return builder.toString();
  +  }
   
     static MarkdownWriter DEFAULT = new MarkdownWriter();
   }
  
positive.code:           return pad + str;
          }
          return str;
        });
      });
  
      return result + items.join(list.tight ? "" : "\n");
    }
  
    String writeInlines(Iterable<Inline> inlines, {String prevEmph, String prevStrong}) {
      if (inlines.length == 1 && prevEmph != null) {
        if (inlines.first is Emph) {
          return writeEmph(inlines.first, delimiter: prevEmph == "*" ? "_" : "*");
        }
        if (inlines.first is Strong) {
          return writeStrong(inlines.first, delimiter: prevEmph == "*" ? "_" : "*");
        }
      }
      StringBuffer result = new StringBuffer();
      Iterator<Inline> it = inlines.iterator;
      int i = 0;
      int last = inlines.length - 1;
      while(it.moveNext()) {
        Inline inline = it.current;
        if (inline is Str) {
          result.write(escapeString(inline.contents));
        } else if (inline is Space) {
          result.write(' ');
        } else if (inline is NonBreakableSpace) {
          result.write('&nbsp;');
        } else if (inline is LineBreak) {
          result.write('\\\n');
        } else if (inline is Emph) {
          result.write(writeEmph(inline));
        } else if (inline is Strong) {
          result.write(writeStrong(inline));
        } else if (inline is Link) {
          result.write(writeLink(inline));
        } else if (inline is Image) {
          result.write(writeImage(inline));
        } else if (inline is Code) {
          result.write(writeCodeInline(inline));
        } else if (inline is RawInline) {
          result.write(inline.contents);
        } else {
          throw new UnimplementedError(inline.toString());
        }
  
        ++i;
      }
  
      return result.toString();
    }
  
    RegExp escapedChars = new RegExp(r'[!\"#\$%&' r"'()*+,-./:;<=>?@\[\\\]^_`{|}~]");
    String escapeString(String str) => str.replaceAllMapped(escapedChars, (Match m) => r"\" + m.group(0));
  
    String writeCodeInline(Code code) {
      String fence = '`' * code.fenceSize;
      String contents = code.contents;
      if (contents == '') {
  
negative.code: 
  import 'definitions.dart';
  
  class _MarkdownBuilder extends StringBuffer {
    Map<String, Target> _references;
  
  
    _MarkdownBuilder([this._references]) : super();
  
  
    void writeDocument(Document document) {
      writeBlocks(document.contents);
      write("\n\n");
      writeReferences();
    }
  
  
    void writeBlocks(Iterable<Block> blocks,
                       {bool tight: false, String unorderedListChar: "*"}) {
      Block prevBlock = null;
      Iterator<Block> it = blocks.iterator;
      bool first = true;
  