[DRE-commits] [ruby-maruku] 03/04: Imported Upstream version 0.7.1

Jonas Genannt jonas at brachium-system.net
Sat Feb 15 21:01:27 UTC 2014


This is an automated email from the git hooks/post-receive script.

hggh-guest pushed a commit to branch master
in repository ruby-maruku.

commit 8736977579ea94fa0b15ea740c4fae44dce1f64c
Author: Jonas Genannt <jonas at brachium-system.net>
Date:   Sat Feb 15 21:55:55 2014 +0100

    Imported Upstream version 0.7.1
---
 MIT-LICENSE.txt                                    |   20 +
 Rakefile                                           |   73 -
 bin/marudown                                       |   29 -
 bin/maruku                                         |  305 ++--
 bin/marutest                                       |  345 ----
 bin/marutex                                        |   31 +-
 checksums.yaml.gz                                  |  Bin 0 -> 270 bytes
 checksums.yaml.gz.sig                              |  Bin 0 -> 256 bytes
 data.tar.gz.sig                                    |  Bin 0 -> 256 bytes
 data/entities.xml                                  |  261 +++
 docs/changelog.md                                  |  334 ----
 docs/markdown_syntax.md                            |   30 +-
 docs/math.md                                       |   32 +-
 lib/maruku.rb                                      |  142 +-
 lib/maruku/attributes.rb                           |  323 ++--
 lib/maruku/defaults.rb                             |  112 +-
 lib/maruku/document.rb                             |   43 +
 lib/maruku/element.rb                              |  127 ++
 lib/maruku/errors.rb                               |   71 +
 lib/maruku/errors_management.rb                    |   92 -
 lib/maruku/ext/div.rb                              |  218 ++-
 lib/maruku/ext/fenced_code.rb                      |   97 +
 lib/maruku/ext/math.rb                             |   48 +-
 lib/maruku/ext/math/elements.rb                    |   46 +-
 lib/maruku/ext/math/latex_fix.rb                   |   12 -
 lib/maruku/ext/math/mathml_engines/blahtex.rb      |  196 +-
 lib/maruku/ext/math/mathml_engines/itex2mml.rb     |   59 +-
 lib/maruku/ext/math/mathml_engines/none.rb         |   30 +-
 lib/maruku/ext/math/mathml_engines/ritex.rb        |    6 +-
 lib/maruku/ext/math/parsing.rb                     |  220 ++-
 lib/maruku/ext/math/to_html.rb                     |  364 ++--
 lib/maruku/ext/math/to_latex.rb                    |   51 +-
 lib/maruku/helpers.rb                              |  415 ++---
 lib/maruku/html.rb                                 |  251 +++
 lib/maruku/input/charsource.rb                     |  591 +++---
 lib/maruku/input/extensions.rb                     |  125 +-
 lib/maruku/input/html_helper.rb                    |  422 +++--
 lib/maruku/input/linesource.rb                     |  200 +--
 lib/maruku/input/mdline.rb                         |  131 ++
 lib/maruku/input/parse_block.rb                    | 1340 +++++++-------
 lib/maruku/input/parse_doc.rb                      |  362 ++--
 lib/maruku/input/parse_span.rb                     |  657 +++++++
 lib/maruku/input/parse_span_better.rb              |  746 --------
 lib/maruku/input/rubypants.rb                      |  341 ++--
 lib/maruku/input/type_detection.rb                 |  147 --
 lib/maruku/inspect_element.rb                      |   60 +
 lib/maruku/maruku.rb                               |   44 +-
 lib/maruku/output/entity_table.rb                  |   33 +
 lib/maruku/output/s5/fancy.rb                      |  924 +++++-----
 lib/maruku/output/s5/to_s5.rb                      |  250 ++-
 lib/maruku/output/to_html.rb                       | 1890 ++++++++++----------
 lib/maruku/output/to_latex.rb                      | 1127 ++++++------
 lib/maruku/output/to_latex_entities.rb             |  367 ----
 lib/maruku/output/to_latex_strings.rb              |   64 -
 lib/maruku/output/to_markdown.rb                   |  369 ++--
 lib/maruku/output/to_s.rb                          |   62 +-
 lib/maruku/string_utils.rb                         |  308 ++--
 lib/maruku/structures.rb                           |  167 --
 lib/maruku/structures_inspect.rb                   |   87 -
 lib/maruku/structures_iterators.rb                 |   61 -
 lib/maruku/tests/benchmark.rb                      |   82 -
 lib/maruku/tests/new_parser.rb                     |  373 ----
 lib/maruku/tests/tests.rb                          |  136 --
 lib/maruku/toc.rb                                  |  381 ++--
 lib/maruku/usage/example1.rb                       |   33 -
 lib/maruku/version.rb                              |   71 +-
 maruku_gem.rb                                      |   33 -
 metadata.gz.sig                                    |    3 +
 metadata.yml                                       |  433 ++---
 spec/block_docs/abbrev.md                          |  776 ++++++++
 .../unittest => spec/block_docs}/abbreviations.md  |   31 +-
 {tests/unittest => spec/block_docs}/alt.md         |   16 +-
 .../unittest/pending => spec/block_docs}/amps.md   |   14 +-
 spec/block_docs/attribute_sanitize.md              |   22 +
 .../block_docs}/attributes/att2.md                 |   12 -
 .../block_docs}/attributes/att3.md                 |   16 +-
 .../block_docs}/attributes/attributes.md           |   28 +-
 .../block_docs}/attributes/circular.md             |   12 -
 .../block_docs}/attributes/default.md              |   14 +-
 spec/block_docs/auto_cdata.md                      |   48 +
 {tests/unittest => spec/block_docs}/blank.md       |   12 -
 .../unittest => spec/block_docs}/blanks_in_code.md |   31 +-
 .../unittest/loss.md => spec/block_docs/bug_def.md |   24 +-
 {tests/unittest => spec/block_docs}/bug_table.md   |   26 +-
 {tests/unittest => spec/block_docs}/code.md        |   21 +-
 {tests/unittest => spec/block_docs}/code2.md       |   18 +-
 {tests/unittest => spec/block_docs}/code3.md       |   28 +-
 spec/block_docs/code4.md                           |   79 +
 {tests/unittest => spec/block_docs}/data_loss.md   |   16 +-
 spec/block_docs/div_without_newline.md             |   16 +
 {tests/unittest => spec/block_docs}/divs/div1.md   |   12 -
 {tests/unittest => spec/block_docs}/divs/div2.md   |   12 -
 .../unittest => spec/block_docs}/divs/div3_nest.md |   18 +-
 {tests/unittest => spec/block_docs}/easy.md        |   14 +-
 spec/block_docs/email.md                           |   29 +
 spec/block_docs/empty_cells.md                     |   31 +
 .../block_docs}/encoding/iso-8859-1.md             |   15 +-
 .../unittest => spec/block_docs}/encoding/utf-8.md |   12 -
 {tests/unittest => spec/block_docs}/entities.md    |   74 +-
 .../unittest/notyet => spec/block_docs}/escape.md  |   16 +-
 {tests/unittest => spec/block_docs}/escaping.md    |   33 +-
 {tests/unittest => spec/block_docs}/extra_dl.md    |   15 +-
 .../block_docs}/extra_header_id.md                 |   34 +-
 .../unittest => spec/block_docs}/extra_table1.md   |   30 +-
 spec/block_docs/fenced_code_blocks.md              |   58 +
 spec/block_docs/fenced_code_blocks_highlighted.md  |   17 +
 {tests/unittest => spec/block_docs}/footnotes.md   |   36 +-
 spec/block_docs/footnotes2.md                      |   81 +
 spec/block_docs/hard.md                            |   25 +
 spec/block_docs/header_after_par.md                |   62 +
 {tests/unittest => spec/block_docs}/headers.md     |   28 +-
 .../unittest => spec/block_docs}/hex_entities.md   |   25 +-
 {tests/unittest => spec/block_docs}/hrule.md       |   17 +-
 {tests/unittest => spec/block_docs}/html3.md       |   14 +-
 {tests/unittest => spec/block_docs}/html4.md       |   16 +-
 {tests/unittest => spec/block_docs}/html5.md       |   16 +-
 spec/block_docs/html_block_in_para.md              |   22 +
 spec/block_docs/html_inline.md                     |   25 +
 spec/block_docs/html_trailing.md                   |   31 +
 spec/block_docs/ie.md                              |   62 +
 .../tab_is_blank.md => spec/block_docs/iframe.md   |   27 +-
 spec/block_docs/ignore_bad_header.md               |    9 +
 {tests/unittest => spec/block_docs}/images.md      |   50 +-
 {tests/unittest => spec/block_docs}/images2.md     |   24 +-
 {tests/unittest => spec/block_docs}/inline_html.md |  104 +-
 .../unittest => spec/block_docs}/inline_html2.md   |   14 +-
 spec/block_docs/inline_html_beginning.md           |   10 +
 spec/block_docs/issue106.md                        |   78 +
 spec/block_docs/issue115.md                        |   20 +
 spec/block_docs/issue117.md                        |   13 +
 spec/block_docs/issue120.md                        |   48 +
 spec/block_docs/issue123.md                        |   11 +
 spec/block_docs/issue124.md                        |   16 +
 spec/block_docs/issue20.md                         |    9 +
 spec/block_docs/issue26.md                         |   22 +
 spec/block_docs/issue29.md                         |    9 +
 spec/block_docs/issue30.md                         |   30 +
 spec/block_docs/issue31.md                         |   25 +
 spec/block_docs/issue40.md                         |   52 +
 spec/block_docs/issue64.md                         |   55 +
 spec/block_docs/issue67.md                         |   19 +
 spec/block_docs/issue70.md                         |   11 +
 spec/block_docs/issue72.md                         |   17 +
 spec/block_docs/issue74.md                         |   38 +
 spec/block_docs/issue79.md                         |   15 +
 spec/block_docs/issue83.md                         |   13 +
 spec/block_docs/issue85.md                         |   25 +
 spec/block_docs/issue88.md                         |   19 +
 spec/block_docs/issue89.md                         |   12 +
 spec/block_docs/issue90.md                         |   38 +
 .../unittest/pending => spec/block_docs}/link.md   |   39 +-
 {tests/unittest => spec/block_docs}/links.md       |   65 +-
 spec/block_docs/links2.md                          |   21 +
 {tests/unittest => spec/block_docs}/list1.md       |   12 -
 {tests/unittest => spec/block_docs}/list12.md      |   16 +-
 {tests/unittest => spec/block_docs}/list2.md       |   16 +-
 spec/block_docs/list_multipara.md                  |   42 +
 {tests/unittest => spec/block_docs}/lists.md       |   57 +-
 {tests/unittest => spec/block_docs}/lists10.md     |   16 +-
 .../unittest/loss.md => spec/block_docs/lists11.md |   29 +-
 spec/block_docs/lists12.md                         |   43 +
 spec/block_docs/lists13.md                         |   55 +
 spec/block_docs/lists14.md                         |   61 +
 spec/block_docs/lists15.md                         |   36 +
 spec/block_docs/lists6.md                          |   88 +
 spec/block_docs/lists7b.md                         |   58 +
 spec/block_docs/lists9.md                          |   53 +
 .../block_docs}/lists_after_paragraph.md           |   44 +-
 spec/block_docs/lists_blank.md                     |   35 +
 .../block_docs/lists_blockquote_code.md            |   16 +-
 .../block_docs/lists_need_blank_line.md            |   71 +-
 spec/block_docs/lists_nested.md                    |   44 +
 spec/block_docs/lists_nested_blankline.md          |   34 +
 spec/block_docs/lists_nested_deep.md               |   43 +
 {tests/unittest => spec/block_docs}/lists_ol.md    |   99 +-
 spec/block_docs/lists_paraindent.md                |   42 +
 spec/block_docs/lists_tab.md                       |   54 +
 spec/block_docs/loss.md                            |   17 +
 spec/block_docs/math-blahtex/equations.md          |   29 +
 spec/block_docs/math-blahtex/inline.md             |   48 +
 spec/block_docs/math-blahtex/math2.md              |   52 +
 spec/block_docs/math-blahtex/table.md              |   25 +
 spec/block_docs/math/embedded_invalid_svg.md       |  108 ++
 spec/block_docs/math/embedded_svg.md               |  136 ++
 spec/block_docs/math/equations.md                  |   49 +
 spec/block_docs/math/inline.md                     |   46 +
 spec/block_docs/math/math2.md                      |   53 +
 .../unittest => spec/block_docs}/math/notmath.md   |   12 -
 spec/block_docs/math/raw_mathml.md                 |   87 +
 spec/block_docs/math/spaces_after_inline_math.md   |   17 +
 spec/block_docs/math/table.md                      |   25 +
 {tests/unittest => spec/block_docs}/math/table2.md |   34 +-
 {tests/unittest => spec/block_docs}/misc_sw.md     |  299 ++--
 {tests/unittest => spec/block_docs}/olist.md       |   24 +-
 {tests/unittest => spec/block_docs}/one.md         |   12 -
 {tests/unittest => spec/block_docs}/paragraph.md   |   12 -
 .../block_docs}/paragraph_rules/dont_merge_ref.md  |   16 +-
 .../block_docs}/paragraph_rules/tab_is_blank.md    |   12 -
 {tests/unittest => spec/block_docs}/paragraphs.md  |   14 +-
 .../block_docs}/recover/recover_links.md           |   20 +-
 .../ref.md => spec/block_docs/ref_with_period.md   |   23 +-
 spec/block_docs/ref_with_title.md                  |   22 +
 .../block_docs}/references/long_example.md         |   39 +-
 .../block_docs}/references/spaces_and_numbers.md   |   12 -
 {tests/unittest => spec/block_docs}/smartypants.md |   55 +-
 {tests/unittest => spec/block_docs}/syntax_hl.md   |   30 +-
 .../block_docs}/table_attributes.md                |   26 +-
 spec/block_docs/table_colspan.md                   |   41 +
 spec/block_docs/tables.md                          |   47 +
 spec/block_docs/tables2.md                         |   74 +
 {tests/unittest => spec/block_docs}/test.md        |   14 +-
 .../unittest/notyet => spec/block_docs}/ticks.md   |   14 +-
 spec/block_docs/toc.md                             |   87 +
 .../notyet => spec/block_docs}/triggering.md       |   39 +-
 .../block_docs}/underscore_in_words.md             |   12 -
 {tests/unittest => spec/block_docs}/wrapping.md    |   20 +-
 spec/block_docs/xml.md                             |   33 +
 spec/block_docs/xml3.md                            |   24 +
 spec/block_docs/xml_comments.md                    |   32 +
 .../block_docs}/xml_instruction.md                 |   29 +-
 spec/block_spec.rb                                 |  110 ++
 spec/cli_spec.rb                                   |    8 +
 spec/span_spec.rb                                  |  256 +++
 spec/spec_helper.rb                                |    3 +
 spec/to_html_utf8_spec.rb                          |   13 +
 tests/bugs/code_in_links.md                        |  101 --
 tests/bugs/complex_escaping.md                     |   38 -
 tests/math/syntax.md                               |   46 -
 tests/math_usage/document.md                       |   13 -
 tests/others/abbreviations.md                      |   11 -
 tests/others/blank.md                              |    4 -
 tests/others/code.md                               |    5 -
 tests/others/code2.md                              |    8 -
 tests/others/code3.md                              |   16 -
 tests/others/email.md                              |    4 -
 tests/others/entities.md                           |   19 -
 tests/others/escaping.md                           |   16 -
 tests/others/extra_dl.md                           |  101 --
 tests/others/extra_header_id.md                    |   13 -
 tests/others/extra_table1.md                       |   40 -
 tests/others/footnotes.md                          |   17 -
 tests/others/headers.md                            |   10 -
 tests/others/hrule.md                              |   10 -
 tests/others/images.md                             |   20 -
 tests/others/inline_html.md                        |   42 -
 tests/others/links.md                              |   38 -
 tests/others/list1.md                              |    4 -
 tests/others/list2.md                              |    5 -
 tests/others/list3.md                              |    8 -
 tests/others/lists.md                              |   32 -
 tests/others/lists_after_paragraph.md              |   44 -
 tests/others/lists_ol.md                           |   39 -
 tests/others/misc_sw.md                            |  105 --
 tests/others/one.md                                |    1 -
 tests/others/paragraphs.md                         |   13 -
 tests/others/sss06.md                              |  352 ----
 tests/others/test.md                               |    4 -
 tests/s5/s5profiling.md                            |   48 -
 tests/unittest/bug_def.md                          |   28 -
 tests/unittest/email.md                            |   32 -
 tests/unittest/hang.md                             |   29 -
 tests/unittest/html2.md                            |   34 -
 tests/unittest/ie.md                               |   61 -
 tests/unittest/links2.md                           |   34 -
 tests/unittest/lists11.md                          |   28 -
 tests/unittest/lists6.md                           |   53 -
 tests/unittest/lists9.md                           |   76 -
 tests/unittest/math/equations.md                   |   86 -
 tests/unittest/math/inline.md                      |   58 -
 tests/unittest/math/math2.md                       |   57 -
 tests/unittest/math/table.md                       |   37 -
 tests/unittest/notyet/header_after_par.md          |   70 -
 tests/unittest/pending/empty_cells.md              |   49 -
 tests/unittest/red_tests/abbrev.md                 | 1388 --------------
 tests/unittest/red_tests/lists7.md                 |   68 -
 tests/unittest/red_tests/lists7b.md                |  128 --
 tests/unittest/red_tests/lists8.md                 |   76 -
 tests/unittest/red_tests/xml.md                    |   70 -
 tests/unittest/xml2.md                             |   31 -
 tests/unittest/xml3.md                             |   38 -
 tests/utf8-files/simple.md                         |    1 -
 unit_test_block.sh                                 |    5 -
 unit_test_span.sh                                  |    3 -
 283 files changed, 12448 insertions(+), 14494 deletions(-)

diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt
new file mode 100644
index 0000000..f1c93f6
--- /dev/null
+++ b/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2006 Andrea Censi
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Rakefile b/Rakefile
deleted file mode 100644
index 9413e4d..0000000
--- a/Rakefile
+++ /dev/null
@@ -1,73 +0,0 @@
-require 'rubygems'
-Gem::manage_gems
-require 'rake/gempackagetask'
-
-require 'maruku_gem'
-
-task :default => [:package]
-
-Rake::GemPackageTask.new($spec) do |pkg|
-  pkg.need_zip = true
-  pkg.need_tar = true
-end
-
-PKG_NAME = 'maruku'
-PKG_FILE_NAME = "#{PKG_NAME}-#{MaRuKu::Version}"
-RUBY_FORGE_PROJECT = PKG_NAME
-RUBY_FORGE_USER = 'andrea'
-
-RELEASE_NAME  = MaRuKu::Version
-RUBY_FORGE_GROUPID = '2795'
-RUBY_FORGE_PACKAGEID = '3292'
-
-desc "Publish the release files to RubyForge."
-task :release => [:gem, :package] do
-	system("rubyforge login --username #{RUBY_FORGE_USER}")
-
-	gem = "pkg/#{PKG_FILE_NAME}.gem"
-	# -n notes/#{Maruku::Version}.txt
-	cmd = "rubyforge  add_release %s %s \"%s\" %s" %
-		[RUBY_FORGE_GROUPID, RUBY_FORGE_PACKAGEID, RELEASE_NAME, gem]
-	
-	puts cmd
-	system(cmd)
-	
-	files = ["gem", "tgz", "zip"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
-	files.each do |file|
-#		system("rubyforge add_file %s %s %s %s" %
-#		[RUBY_FORGE_GROUPID, RUBY_FORGE_PACKAGEID, RELEASE_NAME, file])
-  end
-end
-
-task :test => [:markdown_span_tests, :markdown_block_tests]
-
-task :markdown_block_tests do
-	tests = Dir['tests/unittest/**/*.md'].join(' ')
-	puts "Executing tests #{tests}"
-#	ok = marutest(tests)
-	ok = system "ruby -Ilib bin/marutest #{tests}"
-	raise "Failed block unittest" if not ok
-end
-
-task :markdown_span_tests do
-	ok = system( "ruby -Ilib lib/maruku/tests/new_parser.rb v b")
-	raise "Failed span unittest" if not ok
-end
-
-require 'rake/rdoctask'
-
-Rake::RDocTask.new do |rdoc|
-	files = [#'README', 'LICENSE', 'COPYING', 
-		'lib/**/*.rb', 
-		'rdoc/*.rdoc'#, 'test/*.rb'
-	]
-	rdoc.rdoc_files.add(files)
-	rdoc.main = "rdoc/main.rdoc" # page to start on
-	rdoc.title = "Maruku Documentation"
-	rdoc.template = "jamis.rb"
-	rdoc.rdoc_dir = 'doc' # rdoc output folder
-	rdoc.options << '--line-numbers' << '--inline-source'
-end
-
-
-
diff --git a/bin/marudown b/bin/marudown
deleted file mode 100644
index c5f5252..0000000
--- a/bin/marudown
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'maruku'
-
-	# If we are given filenames, convert each file 
-	if not ARGV.empty?
-		ARGV.each do |f|
-			puts "Opening #{f}"
-	
-			# read file content
-			input =  File.open(f,'r').read
-		
-			# create Maruku
-			doc = Maruku.new(input, {:on_error=>:warning})
-			# convert to a complete html document
-			output = doc.to_md
-	
-			# write to file
-			dir = File.dirname(f)
-			filename = File.basename(f, File.extname(f)) + ".txt"
-
-			output = File.join(dir, filename)	
-			File.open(output,'w') do |f| f.puts html end
-		end
-	else
-		# else, act as a filter
-		data = $stdin.read
-		puts Maruku.new(data, {:on_error=>:warning}).to_md
-	end
diff --git a/bin/maruku b/bin/maruku
old mode 100644
new mode 100755
index 66fbc1d..e0261a6
--- a/bin/maruku
+++ b/bin/maruku
@@ -1,13 +1,22 @@
 #!/usr/bin/env ruby
 
+dir = File.join(File.dirname(__FILE__), '..', 'lib')
+$LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
+
 require 'maruku'
 require 'optparse'
 
 
 def cli_puts(s)
-	$stderr.puts(s) if MaRuKu::Globals[:verbose]	
+  $stderr.puts(s) if MaRuKu::Globals[:verbose]
 end
 
+def benchmark(section)
+  t = Time.now
+  res = yield
+  cli_puts("%s finished in %.2f seconds." % [section, Time.now - t])
+  res
+end
 
 export = :html
 break_on_error = false
@@ -16,166 +25,158 @@ using_mathml = false
 output_file = nil
 
 opt = OptionParser.new do |opts|
-	opts.banner = "Usage: maruku [options] [file1.md [file2.md ..."
-
-	opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
-		MaRuKu::Globals[:verbose] = v end
-	opts.on("-u", "--[no-]unsafe", "Use unsafe features") do |v|
-		MaRuKu::Globals[:unsafe_features] = v end
-
-	opts.on("-b", "Break on error") do |v|
-		break_on_error = true end
-
-
-	opts.on("-i", "--math-images ENGINE", "Uses ENGINE to render TeX to PNG.") do |s|
-		using_math = true
-		MaRuKu::Globals[:html_math_output_png] = true
-		MaRuKu::Globals[:html_math_output_mathml] = false
-		MaRuKu::Globals[:html_png_engine] = s
-		cli_puts "Using png engine #{s}."
-	end
-
-	opts.on("-m", "--math-engine ENGINE", "Uses ENGINE to render MathML") do |s|
-		MaRuKu::Globals[:html_math_output_png] = false
-		MaRuKu::Globals[:html_math_output_mathml] = true
-		using_math = true
-		using_mathml = true
-		MaRuKu::Globals[:html_math_engine] = s
-	end
-
-	opts.on("-o", "--output FILE", "Output filename") do |s|
-		output_file = s
-	end
-
-	opts.on_tail("--pdf",  "Write PDF","First writes LaTeX, then calls pdflatex." ) do export = :pdf  end
-	opts.on_tail("--s5", "Write S5 slideshow") do export = :s5 end
-	opts.on_tail("--html", "Write HTML") do export = :html end
-	opts.on_tail("--html-frag", "Write the contents of the BODY.") do export = :html_frag end
-	opts.on_tail("--tex",  "Write LaTeX" ) do export = :tex  end
-	opts.on_tail("--inspect",  "Shows the parsing result" ) do export = :inspect  end
-
-	opts.on_tail("--version", "Show version") do
-		puts "Maruku #{MaRuKu::Version}"; exit
-	end
-
-	opts.on_tail("--ext EXTENSIONS",  "Use maruku extensions (comma separated)" ) do |s|
-	  s.split(",").each do |e| require "maruku/ext/#{e}"; end
-	end
-
-	opts.on_tail("-h", "--help", "Show this message") do
-		puts opts
-		exit
-	end
-
+  opts.banner = "Usage: #{File.basename($0)} [options] [file1.md] [file2.md] ..."
+
+  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
+    MaRuKu::Globals[:verbose] = v
+  end
+
+  opts.on("-u", "--[no-]unsafe", "Use unsafe features") do |v|
+    MaRuKu::Globals[:unsafe_features] = v
+  end
+
+  opts.on("-b", "--[no-]break", "Break on error") do |v|
+    break_on_error = v
+  end
+
+
+  opts.on("-i", "--math-images ENGINE", "Use ENGINE to render TeX to PNG") do |s|
+    using_math = true
+    MaRuKu::Globals[:html_math_output_png] = true
+    MaRuKu::Globals[:html_math_output_mathml] = false
+    MaRuKu::Globals[:html_png_engine] = s
+    cli_puts "Using png engine #{s}."
+  end
+
+  opts.on("-m", "--math-engine ENGINE", "Use ENGINE to render MathML") do |s|
+    MaRuKu::Globals[:html_math_output_png] = false
+    MaRuKu::Globals[:html_math_output_mathml] = true
+    using_math = true
+    using_mathml = true
+    MaRuKu::Globals[:html_math_engine] = s
+  end
+
+  opts.on("-o", "--output FILE", "Output filename (`-o -' writes to stdout)") {|s| output_file = s}
+
+  opts.on_tail("--pdf", "Output PDF;", "first writes LaTeX, then calls pdflatex") {export = :pdf}
+  opts.on_tail("--s5", "Output S5 slideshow") {export = :s5}
+  opts.on_tail("--html", "Output HTML") {export = :html}
+  opts.on_tail("--html-frag", "Output the contents of the <body> tag") {export = :html_frag}
+  opts.on_tail("--tex", "Output LaTeX" ) {export = :tex}
+  opts.on_tail("--markdown", "Output Markdown" ) {export = :markdown}
+  opts.on_tail("--inspect", "Output the parse tree") {export = :inspect}
+
+  opts.on_tail("--ext EXTENSIONS", "Use Maruku extensions (comma separated)") do |s|
+    s.split(",").each {|e| require "maruku/ext/#{e}"}
+  end
+
+  opts.on_tail("-h", "--help", "Show this help message") do
+    puts opts
+    exit
+  end
+
+  opts.on_tail("--version", "Show version") do
+    puts "Maruku #{MaRuKu::Version}"
+    exit
+  end
 end
 
-begin 
-opt.parse!
-rescue OptionParser::InvalidOption=>e
-	$stderr.puts e
-	$stderr.puts opt
-	exit
+begin
+  opt.parse!
+rescue OptionParser::InvalidOption => e
+  $stderr.puts e
+  $stderr.puts opt
+  exit 1
 end
 
 
 if using_math
-	cli_puts "Using Math extensions."
-	require 'maruku/ext/math'
+  cli_puts "Using Math extensions."
+  require 'maruku/ext/math'
 end
 
-#p ARGV
-#p MaRuKu::Globals
 
+unless ARGV.empty?
+  if ARGV.size > 1 && output_file
+    $stderr.puts "Can't write #{ARGV.map {|f| f.inspect}.join(' and ')} to #{output_file.inspect}"
+    exit 1
+  end
 
-inputs =
-# If we are given filenames, convert each file 
-if not ARGV.empty?
-	ARGV.map do |f|
-		# read file content
-		cli_puts "Reading from file #{f.inspect}." 
-		[f, File.open(f,'r').read]
-	end
+  # If we are given filenames, convert each file
+  ARGV.map do |f|
+    # read file content
+    cli_puts "Reading from file #{f.inspect}."
+    [f, File.read(f)]
+  end
 else
-	export = :html_frag if export == :html
-	export = :tex_frag if export == :tex
-	
-	cli_puts  "Reading from standard input."
-	[[nil, $stdin.read]]
+  export = :html_frag if export == :html
+  export = :tex_frag if export == :tex
+
+  cli_puts  "Reading from standard input."
+  [[nil, $stdin.read]]
+end.each do |filename, input|
+  doc = benchmark("Parsing") {Maruku.new(input, :on_error => (break_on_error ? :raise : :warning))}
+
+  out = ""
+  suffix = "?"
+  benchmark("Rendering") do
+    case export
+    when :html
+      suffix = using_mathml ? '.xhtml' : '.html'
+      out = doc.to_html_document
+    when :html_frag
+      suffix = '.html_frag'
+      out = doc.to_html
+    when :pdf, :tex
+      suffix = '.tex'
+      out = doc.to_latex_document
+    when :tex_frag
+      suffix = '.tex_frag'
+      out = doc.to_latex
+    when :inspect
+      suffix = '.txt'
+      out = doc.inspect
+    when :markdown
+      suffix = '.md'
+      out = doc.to_md
+    when :s5
+      suffix = '_s5slides.html'
+      out = doc.to_s5(:content_only => false, :print_slides => true)
+    end
+  end
+
+  if (output_file.nil? && filename.nil?) || output_file == "-"
+    if export == :pdf
+      $stderr.puts "Can't write PDF to stdout"
+      exit 1
+    end
+
+    cli_puts "Writing to standard output"
+    $stdout.puts out
+    next
+  end
+
+  if output_file
+    job = File.basename(output_file, File.extname(output_file))
+  else
+    dir = File.dirname(filename)
+    job = File.join(dir, File.basename(filename, File.extname(filename)))
+    output_file = job + suffix
+  end
+
+  if export == :pdf
+    cli_puts "Writing to #{job}.tex"
+    File.open("#{job}.tex", 'w') {|f| f.puts out}
+    cmd = ["pdflatex", "#{job}.tex", "-interaction=nonstopmode"]
+    cmd << "-output-directory=#{dir}" if dir
+    cli_puts "maruku: executing $ #{cmd.join(' ')}"
+
+    # run twice for cross references
+    system *cmd
+    system *cmd
+    next
+  end
+
+  cli_puts "Writing to #{output_file.inspect}"
+  File.open(output_file, 'w') {|f| f.puts out}
 end
-
-inputs.each do |f, input|
-	
-		# create Maruku
-		params = {}
-		params[:on_error] = break_on_error ? :raise : :warning
-
-		t = Time.now
-		doc = Maruku.new(input, params)
-
-		cli_puts ("Parsing in %.2f seconds." % (Time.now-t))
-
-		out=""; suffix = "?"
-		t = Time.now
-		case export
-		when :html 
-			suffix = using_mathml ? '.xhtml' : '.html'
-			out = doc.to_html_document( {:indent => -1})
-		when :html_frag 
-			suffix='.html_frag'
-			out = doc.to_html( {:indent => -1})
-		when :pdf, :tex
-			suffix='.tex'
-			out = doc.to_latex_document
-		when :tex_frag
-			suffix='.tex_frag'
-			out = doc.to_latex
-		when :inspect
-			suffix='.txt'
-			out = doc.inspect
-		when :markdown
-			suffix='.pretty_md'
-			out = doc.to_markdown
-		when :s5
-			suffix='_s5slides.html'
-			out = doc.to_s5({:content_only => false})
-		end
-
-		cli_puts("Rendering in %.2f seconds." % (Time.now-t))
-	
-		# write to file or stdout
-		if f
-			
-			if not output_file 
-				dir = File.dirname(f)
-				job = File.join(dir, File.basename(f, File.extname(f)))
-				output_file = job  + suffix
-			else
-				job = File.basename(output_file, File.extname(output_file))
-			end
-			
-			if output_file == "-"
-				cli_puts "Writing to standard output"
-				$stdout.puts out
-			else
-			
-				if not (export == :pdf)
-					cli_puts "Writing to #{output_file}"
-					File.open(output_file,'w') do |f| f.puts out end
-				else
-					cli_puts "Writing to #{job}.tex"
-					File.open("#{job}.tex",'w') do |f| f.puts out end
-					cmd = "pdflatex '#{job}.tex' -interaction=nonstopmode "+
-					      "'-output-directory=#{dir}' "
-					cli_puts "maruku: executing $ #{cmd}"
-					# run twice for cross references
-					system cmd 
-					system cmd
-				end
-			
-			end
-		else # write to stdout
-			cli_puts "Writing to standard output"
-			$stdout.puts out
-		end
-	end
-	
diff --git a/bin/marutest b/bin/marutest
deleted file mode 100644
index 4ff49dc..0000000
--- a/bin/marutest
+++ /dev/null
@@ -1,345 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'maruku'
-require 'maruku/textile2'
-
-$marutest_language = :markdown
-
-#MARKER = "\n***EOF***\n"
-SPLIT = %r{\n\*\*\*[^\*]+\*\*\*\n}m
-
-def marker(x)
-	"\n*** Output of #{x} ***\n"
-end
-
-def write_lines(i, j, lines, prefix, i_star)
-	i = [i, 0].max
-	j = [j, lines.size-1].min
-	for a in i..j
-		l = lines[a].gsub(/\t/,'  ')
-		puts( ("%s %3d" % [prefix, a]) + 
-			(a==i_star ? " -->" : "    ")+lines[a])
-	end
-end
-
-# a = expected   b = found 
-def equals(a, b)
-	a = a.split("\n")
-	b = b.split("\n")
-	
-	for i in 0..([a.size-1,b.size-1].max)
-		la = a[i]
-		lb = b[i]
-		if la != lb
-			puts "\n"
-			
-			
-			write_lines(i-3, i+3, a, "expected", i )
-			write_lines(i-3, i+3, b, "   found", i )
-			return false
-		end
-	end
-	return true
-end
-
-TOTEST = [:inspect,:to_html,:to_latex,:to_md,:to_s]
-
-def run_test(filename, its_ok, verbose=true)
-	# read file content
-	input =  (f=File.open(filename,'r')).read; f.close
-	
-	output_html = File.join(File.dirname(filename), 
-		File.basename(filename, File.extname(filename)) + ".html")	
-	
-	# split the input in sections
-	
-	stuff = input.split(SPLIT)
-	if stuff.size == 1
-		stuff[2] = stuff[0]
-		stuff[0] = "Write a comment here"
-		stuff[1] = "{} # params "
-	end
-
-	comment   = stuff.shift
-	params_s = stuff.shift
-	
-	params = eval(params_s||'{}')
-	if params == nil
-		raise "Null params? #{params_s.inspect}"
-	end
-	
-	markdown  = stuff.shift
-
-#	puts "comment: #{markdown.inspect}"	
-#	puts "markdown: #{markdown.inspect}"
-	
-	failed = []
-	relaxed = []
-	crashed = []
-	actual = {}
-	
-	doc = 
-		if $marutest_language == :markdown
-			Maruku.new(markdown, params)
-		else
-			MaRuKu.textile2(markdown, params)
-		end
-
-	for s in TOTEST
-		begin
-			if s==:to_html
-				actual[s] = doc.to_html
-			else
-				actual[s] = doc.send s
-				raise "Methods #{s} gave nil" if not actual[s]
-			end
-		rescue Exception => e
-			crashed << s
-			actual[s] = e.inspect+ "\n"+ e.backtrace.join("\n")
-			puts actual[s]
-		end
-	end
-
-	File.open(output_html, 'w') do |f|
-		f.write doc.to_html_document
-	end
-
-		begin
-			m = Maruku.new
-			d = m.instance_eval(actual[:inspect])
-		rescue Exception => e
-			s = e.inspect + e.backtrace.join("\n")
-			raise "Inspect is not correct:\n ========\n#{actual[:inspect]}"+
-			"============\n #{s}"
-		end
-
-	expected = {}
-	if (stuff.size < TOTEST.size)
-		$stdout.write " (first time!) "
-		TOTEST.each do |x| expected[x] = actual[x] end
-	else
-		TOTEST.each_index do |i|
-			symbol = TOTEST[i]
-			expected[symbol] = stuff[i]
-#			puts "symbol: #{symbol.inspect} = #{stuff[i].inspect}"
-		end
-	end
-
-	m = Maruku.new
-	
-	
-	if not its_ok.include? :inspect
-		begin
-			d = m.instance_eval(expected[:inspect])
-	#		puts "Eval: #{d.inspect}"
-			expected[:inspect] = d.inspect
-		rescue Exception => e
-			s = e.inspect + e.backtrace.join("\n")
-			raise "Cannot eval user-provided string:\n #{expected[:inspect].to_s}"+
-			"\n #{s}"
-		end
-	end
-
-#	 m.instance_eval(actual[:inspect]) != m.instance_eval(expected[:inspect])	
-
-#	actual[:inspect] = m.instance_eval(actual[:inspect]) 
-#	expected[:inspect] =  m.instance_eval(expected[:inspect])
-
-
-	TOTEST.each do |x|
-		expected[x].strip!
-		actual[x].strip!
-		if not equals(expected[x], actual[x])
-			if its_ok.include? x
-				expected[x] = actual[x]
-				$stdout.write " relax:#{x} "
-				relaxed << x
-			else
-				actual[x] = "-----| WARNING | -----\n" + actual[x].to_s
-				failed << x
-			end
-		end
-	end
-	
-	f = File.open(filename, 'w')
-	
-	f.write comment
-	f.write "\n*** Parameters: ***\n"
-	f.write params_s
-	f.write "\n*** Markdown input: ***\n"
-	f.write markdown
-
-	TOTEST.each do |x|
-		f.write marker(x) 
-		f.write expected[x]
-	end
-	f.write "\n*** EOF ***\n"
-	
-	if not failed.empty? or not crashed.empty? 
-		
-		f.puts "\n\n\n\nFailed tests:   #{failed.inspect} \n" 
-	
-		TOTEST.each do |x|
-			f.write marker(x) 
-			f.write actual[x]
-		end
-
-	else
-		f.puts "\n\n\n\tOK!\n\n\n"
-	end
-
-	
-	if false
-		md_pl = markdown_pl(markdown)
-		
-		f.write "\n*** Output of Markdown.pl ***\n" 
-		f.write md_pl
-	
-		f.write "\n*** Output of Markdown.pl (parsed) ***\n"
-		begin 
-			doc = REXML::Document.new("<div>#{md_pl}</div>",{
-				:compress_whitespace=>['div','p'],
-				:ignore_whitespace_nodes=>['div','p'],
-				:respect_whitespace=>['pre','code']
-			})
-			div = doc.root
-			xml =""
-			div.write_children(xml,indent=1,transitive=true,ie_hack=false)
-			f.write xml
-		rescue Exception=>e
-			f.puts "Error: #{e.inspect}"
-		end
-		f.close
-	else
-		f.write "\n*** Output of Markdown.pl ***\n" 
-		f.write "(not used anymore)"
-	
-		f.write "\n*** Output of Markdown.pl (parsed) ***\n"
-		f.write "(not used anymore)"		
-	end
-	
-	return failed, relaxed, crashed
-end
-
-def markdown_pl(markdown)
-	tmp1 = "/tmp/marutest1"
-	tmp2 = "/tmp/marutest2"
-	File.open(tmp1,'w') do |f| f.puts markdown end
-	system "Markdown.pl < #{tmp1} > #{tmp2}"
-	f = File.open(tmp2,'r')
-	s = f.read
-	f.close
-	s
-end
-
-def passed?(args, arg)
-	if args.include? arg
-		args.delete arg
-		true
-	else
-		false
-	end
-end
-
-def marutest(args)
-	dont_worry = []
-	TOTEST.each do |x|
-		arg = "ok:#{x}"
-	#	puts arg
-		if passed?(args, arg)
-			dont_worry << x
-		end
-	end
-	
-	if passed?(args, 'ok')
-		dont_worry = TOTEST.clone
-	end
-	
-	if dont_worry.size > 0
-		puts "Relaxed on #{dont_worry.inspect}"
-	end
-	
-
-	failed = {}
-	relaxed = {}
-	
-	args.each do |f|
-		$stdout.write  f + ' '*(50-f.size) + " "
-		$stdout.flush
-		tf, tr, tcrashed = run_test(f, dont_worry)
-		
-		tf = tf + tcrashed
-
-		
-		if tr.size > 0
-			$stdout.write " relax #{tr.inspect} "
-		end
-		
-		if tf.size>0
-			$stdout.write " failed on #{tf.inspect} "
-		else
-			$stdout.write " OK "
-		end
-
-		if tcrashed.size > 0
-			$stdout.write "    CRASHED on #{tcrashed.inspect}"
-		end
-
-			$stdout.write "\n"		
-			
-		failed[f]  = tf
-		relaxed[f]  = tr	
-	end
-	
-	num_failed = 0
-	failed_cat = {}
-
-	puts "\n\n\n**** FINAL REPORT ****\n\n"
-
-	
-	if failed.size > 0
-		failed.each do |file, fl|
-			num_failed += fl.size
-			if fl.size > 0
-				puts "\t#{file}\tfailed on #{fl.inspect}"
-			end
-			fl.each do |x|
-				failed_cat[x] = failed_cat[x] || 0
-				failed_cat[x] = failed_cat[x]  + 1
-			end
-		end
-	end
-
-	if dont_worry.size > 0
-		puts "Relaxed on #{dont_worry.inspect}"
-	end
-
-	if relaxed.size > 0
-		relaxed.each do |file, r|
-			if r.size > 0
-				puts "\t#{file}\t\trelaxed on #{r.inspect}"
-			end
-		end
-	end
-	
-	if failed_cat.size > 0
-		puts "\nCategories:\n"
-	
-		failed_cat.each do |x, num|
-			puts "\t#{x.inspect} \tfailed #{num}/#{args.size}"
-		end
-	end
-	
-	return num_failed == 0
-end
-
-if File.basename(__FILE__) == 'marutest'
-	if ARGV.empty?
-		puts "marutest is a tool for running Maruku's unittest."
-		exit 1
-	end
-	ok = marutest(ARGV.clone)
-	
-	exit ok ? 0 : -1 
-end
-
diff --git a/bin/marutex b/bin/marutex
old mode 100644
new mode 100755
index b3ed099..dcdd913
--- a/bin/marutex
+++ b/bin/marutex
@@ -1,31 +1,4 @@
 #!/usr/bin/env ruby
 
-require 'maruku'
-
-if File.basename($0) =~ /^marutex/
-	# Convert each file 
-	ARGV.each do |f|
-		puts "Opening #{f}"
-	
-		# read file content
-		input =  File.open(f,'r').read
-		
-		# create Maruku
-		doc = Maruku.new(input)
-		# convert to a complete html document
-		latex = doc.to_latex_document
-	
-		# write to file
-		dir = File.dirname(f)
-		job = File.join(dir, File.basename(f, File.extname(f)))
-		filename = job + ".tex"
-
-		File.open(filename,'w') do |f| f.puts latex end
-
-		# run twice for cross references
-		system "pdflatex '#{job}'  '-output-directory=#{dir}' "
-		system "pdflatex '#{job}' '-output-directory=#{dir}' "
-		
-#		system "open #{job}.pdf"
-	end
-end
\ No newline at end of file
+ARGV.unshift "--pdf"
+load File.join(File.dirname(__FILE__), "maruku")
diff --git a/checksums.yaml.gz b/checksums.yaml.gz
new file mode 100644
index 0000000..0827fb2
Binary files /dev/null and b/checksums.yaml.gz differ
diff --git a/checksums.yaml.gz.sig b/checksums.yaml.gz.sig
new file mode 100644
index 0000000..06976e5
Binary files /dev/null and b/checksums.yaml.gz.sig differ
diff --git a/data.tar.gz.sig b/data.tar.gz.sig
new file mode 100644
index 0000000..f579aac
Binary files /dev/null and b/data.tar.gz.sig differ
diff --git a/data/entities.xml b/data/entities.xml
new file mode 100644
index 0000000..20f6ad7
--- /dev/null
+++ b/data/entities.xml
@@ -0,0 +1,261 @@
+<!-- A conversion chart for html elements, courtesy of text2html -->
+<chars>
+  <char num='913' name='Alpha' convertTo='$A$' />
+  <char num='914' name='Beta' convertTo='$B$' />
+  <char num='915' name='Gamma' convertTo='$\Gamma$' />
+  <char num='916' name='Delta' convertTo='$\Delta$' />
+  <char num='917' name='Epsilon' convertTo='$E$' />
+  <char num='918' name='Zeta' convertTo='$Z$' />
+  <char num='919' name='Eta' convertTo='$H$' />
+  <char num='920' name='Theta' convertTo='$\Theta$' />
+  <char num='921' name='Iota' convertTo='$I$' />
+  <char num='922' name='Kappa' convertTo='$K$' />
+  <char num='923' name='Lambda' convertTo='$\Lambda$' />
+  <char num='924' name='Mu' convertTo='$M$' />
+  <char num='925' name='Nu' convertTo='$N$' />
+  <char num='926' name='Xi' convertTo='$\Xi$' />
+  <char num='927' name='Omicron' convertTo='$O$' />
+  <char num='928' name='Pi' convertTo='$\Pi$' />
+  <char num='929' name='Rho' convertTo='$P$' />
+  <char num='931' name='Sigma' convertTo='$\Sigma$' />
+  <char num='932' name='Tau' convertTo='$T$' />
+  <char num='933' name='Upsilon' convertTo='$Y$' />
+  <char num='934' name='Phi' convertTo='$\Phi$' />
+  <char num='935' name='Chi' convertTo='$X$' />
+  <char num='936' name='Psi' convertTo='$\Psi$' />
+  <char num='937' name='Omega' convertTo='$\Omega$' />
+  <char num='945' name='alpha' convertTo='$\alpha$' />
+  <char num='946' name='beta' convertTo='$\beta$' />
+  <char num='947' name='gamma' convertTo='$\gamma$' />
+  <char num='948' name='delta' convertTo='$\delta$' />
+  <char num='949' name='epsilon' convertTo='$\epsilon$' />
+  <char num='950' name='zeta' convertTo='$\zeta$' />
+  <char num='951' name='eta' convertTo='$\eta$' />
+  <char num='952' name='theta' convertTo='$\theta$' />
+  <char num='953' name='iota' convertTo='$\iota$' />
+  <char num='954' name='kappa' convertTo='$\kappa$' />
+  <char num='955' name='lambda' convertTo='$\lambda$' />
+  <char num='956' name='mu' convertTo='$\mu$' />
+
+  <char num='957' name='nu' convertTo='$\nu$' />
+  <char num='958' name='xi' convertTo='$\xi$' />
+  <char num='959' name='omicron' convertTo='$o$' />
+  <char num='960' name='pi' convertTo='$\pi$' />
+  <char num='961' name='rho' convertTo='$\rho$' />
+  <char num='963' name='sigma' convertTo='$\sigma$' />
+  <char num='964' name='tau' convertTo='$\tau$' />
+  <char num='965' name='upsilon' convertTo='$\upsilon$' />
+  <char num='966' name='phi' convertTo='$\phi$' />
+
+  <char num='967' name='chi' convertTo='$\chi$' />
+  <char num='968' name='psi' convertTo='$\psi$' />
+  <char num='969' name='omega' convertTo='$\omega$' />
+  <char num='962' name='sigmaf' convertTo='$\varsigma$' />
+  <char num='977' name='thetasym' convertTo='$\vartheta$' />
+  <char num='982' name='piv' convertTo='$\varpi$' />
+  <char num='8230' name='hellip' convertTo='\ldots' />
+  <char num='8242' name='prime' convertTo='$\prime$' />
+  <char num='8254' name='oline' convertTo='-' />
+
+  <char num='8260' name='frasl' convertTo='/' />
+  <char num='8472' name='weierp' convertTo='$\wp$' />
+  <char num='8465' name='image' convertTo='$\Im$' />
+  <char num='8476' name='real' convertTo='$\Re$' />
+  <char num='8501' name='alefsym' convertTo='$\aleph$' />
+  <char num='8226' name='bull' convertTo='$\bullet$' />
+  <char num='8482' name='trade' convertTo='$^{\rm TM}$' /> <!--   exttrademark -->
+  <char num='8592' name='larr' convertTo='$\leftarrow$' />
+
+  <char num='8594' name='rarr' convertTo='$\rightarrow$' />
+  <char num='8593' name='uarr' convertTo='$\uparrow$' />
+  <char num='8595' name='darr' convertTo='$\downarrow$' />
+  <char num='8596' name='harr' convertTo='$\leftrightarrow$' />
+  <char num='8629' name='crarr' convertTo='$\hookleftarrow$' />
+  <char num='8657' name='uArr' convertTo='$\Uparrow$' />
+  <char num='8659' name='dArr' convertTo='$\Downarrow$' />
+  <char num='8656' name='lArr' convertTo='$\Leftarrow$' />
+  <char num='8658' name='rArr' convertTo='$\Rightarrow$' />
+
+  <char num='8660' name='hArr' convertTo='$\Leftrightarrow$' />
+  <char num='8704' name='forall' convertTo='$\forall$' />
+  <char num='8706' name='part' convertTo='$\partial$' />
+  <char num='8707' name='exist' convertTo='$\exists$' />
+  <char num='8709' name='empty' convertTo='$\emptyset$' />
+  <char num='8711' name='nabla' convertTo='$\nabla$' />
+  <char num='8712' name='isin' convertTo='$\in$' />
+  <char num='8715' name='ni' convertTo='$\ni$' />
+  <char num='8713' name='notin' convertTo='$\notin$' />
+
+  <char num='8721' name='sum' convertTo='$\sum$' />
+  <char num='8719' name='prod' convertTo='$\prod$' />
+  <char num='8722' name='minus' convertTo='$-$' />
+  <char num='8727' name='lowast' convertTo='$\ast$' />
+  <char num='8730' name='radic' convertTo='$\surd$' />
+  <char num='8733' name='prop' convertTo='$\propto$' />
+  <char num='8734' name='infin' convertTo='$\infty$' />
+  <char num='8736' name='ang' convertTo='$\angle$' />
+  <char num='8743' name='and' convertTo='$\wedge$' />
+
+  <char num='8744' name='or' convertTo='$\vee$' />
+  <char num='8745' name='cup' convertTo='$\cup$' />
+  <char num='8746' name='cap' convertTo='$\cap$' />
+  <char num='8747' name='int' convertTo='$\int$' />
+  <char num='8756' name='there4' convertTo='$\therefore$' package='amssymb' /> <!-- only AMS -->
+  <char num='8764' name='sim' convertTo='$\sim$' />
+  <char num='8776' name='asymp' convertTo='$\approx$' />
+  <char num='8773' name='cong' convertTo='$\cong$' />
+
+  <char num='8800' name='ne' convertTo='$\neq$' />
+  <char num='8801' name='equiv' convertTo='$\equiv$' />
+  <char num='8804' name='le' convertTo='$\leq$' />
+  <char num='8805' name='ge' convertTo='$\geq$' />
+  <char num='8834' name='sub' convertTo='$\subset$' />
+  <char num='8835' name='sup' convertTo='$\supset$' />
+  <!--  <char num='8838' name='sube' convertTo='$\subseteq$' />-->
+  <char num='8839' name='supe' convertTo='$\supseteq$' />
+  <!--    <char num='8836' name='nsub' convertTo='$\nsubset$'  /> only AMS -->
+
+  <char num='8853' name='oplus' convertTo='$\oplus$' />
+  <char num='8855' name='otimes' convertTo='$\otimes$' />
+  <char num='8869' name='perp' convertTo='$\perp$' />
+  <char num='8901' name='sdot' convertTo='$\cdot$' />
+  <char num='8968' name='rceil' convertTo='$\rceil$' />
+  <char num='8969' name='lceil' convertTo='$\lceil$' />
+  <char num='8970' name='lfloor' convertTo='$\lfloor$' />
+  <char num='8971' name='rfloor' convertTo='$\rfloor$' />
+  <char num='9001' name='rang' convertTo='$\rangle$' />
+
+  <char num='9002' name='lang' convertTo='$\langle$' />
+  <char num='9674' name='loz' convertTo='$\lozenge$' package='amssymb' /> <!-- only AMS -->
+  <char num='9824' name='spades' convertTo='$\spadesuit$' />
+  <char num='9827' name='clubs' convertTo='$\clubsuit$' />
+  <char num='9829' name='hearts' convertTo='$\heartsuit$' />
+  <char num='9830' name='diams' convertTo='$\diamondsuit$' />
+  <char num='38' name='amp' convertTo='\&' />
+  <!--    <char num='34' name='quot' convertTo='\"' />  XXX -->
+  <char num='34' name='quot' convertTo='"' />
+  <char num='39' name='apos' convertTo="'" />
+  <char num='169' name='copy' convertTo='\copyright' />
+
+  <char num='60' name='lt' convertTo='$<$' />
+  <char num='62' name='gt' convertTo='$>$' />
+  <char num='338' name='OElig' convertTo='\OE' />
+  <char num='339' name='oelig' convertTo='\oe' />
+  <char num='352' name='Scaron' convertTo='\v{S}' />
+  <char num='353' name='scaron' convertTo='\v{s}' />
+  <char num='376' name='Yuml' convertTo='\"Y' />
+  <char num='710' name='circ' convertTo='\textasciicircum' />
+  <char num='732' name='tilde' convertTo='\textasciitilde' />
+
+  <char num='8211' name='ndash' convertTo='--' />
+  <char num='8212' name='mdash' convertTo='---' />
+  <char num='8216' name='lsquo' convertTo='`' />
+  <char num='8217' name='rsquo' convertTo="'" /> <!-- XXXX -->
+  <char num='8220' name='ldquo' convertTo='``' />
+  <char num='8221' name='rdquo' convertTo="''" /> <!-- XXXX -->
+  <char num='8224' name='dagger' convertTo='\dag' />
+  <char num='8225' name='Dagger' convertTo='\ddag' />
+  <char num='8240' name='permil' convertTo='\permil' package='wasysym' /> <!-- wasysym package -->
+
+  <char num='8364' name='euro' convertTo='\euro' package='eurosym' /> <!-- eurosym package -->
+  <char num='8249' name='lsaquo' convertTo='\guilsinglleft' package='aeguill'/>
+  <char num='8250' name='rsaquo' convertTo='\guilsinglright' package='aeguill' />
+  <!--    <char num='160' name='nbsp' convertTo='\nolinebreak' />-->
+  <char num='160' name='nbsp' convertTo='~' />
+  <char num='161' name='iexcl' convertTo='\textexclamdown' />
+  <char num='163' name='pound' convertTo='\pounds' />
+  <char num='164' name='curren' convertTo='\currency' package='wasysym' /> <!-- wasysym package -->
+  <char num='165' name='yen' convertTo='\textyen' package='textcomp'/> <!-- textcomp -->
+
+  <char num='166' name='brvbar' convertTo='\brokenvert' /> <!-- wasysym -->
+  <char num='167' name='sect' convertTo='\S' />
+  <char num='171' name='laquo' convertTo='\guillemotleft' package='aeguill'/>
+  <char num='187' name='raquo' convertTo='\guillemotright' package='aeguill'/>
+  <char num='174' name='reg' convertTo='\textregistered' />
+  <char num='170' name='ordf' convertTo='\textordfeminine' />
+  <char num='172' name='not' convertTo='$\neg$' />
+  <!--  <char num='176' name='deg' convertTo='$\degree$' /> mathabx -->
+  <char num='176' name='deg' convertTo='\textdegree' package='textcomp'/>
+
+  <char num='177' name='plusmn' convertTo='$\pm$' />
+  <char num='180' name='acute' convertTo=''' />
+  <char num='181' name='micro' convertTo='$\mu$' />
+  <char num='182' name='para' convertTo='\P' />
+  <char num='183' name='middot' convertTo='$\cdot$' />
+  <char num='186' name='ordm' convertTo='\textordmasculine' />
+  <char num='162' name='cent' convertTo='\cent' package='wasysym' />
+  <char num='185' name='sup1' convertTo='$^1$' />
+
+  <char num='178' name='sup2' convertTo='$^2$' />
+  <char num='179' name='sup3' convertTo='$^3$' />
+  <char num='189' name='frac12' convertTo='$\frac{1}{2}$' />
+  <char num='188' name='frac14' convertTo='$\frac{1}{4}$' />
+  <char num='190' name='frac34' convertTo='$\frac{3}{4}$' />
+  <char num='192' name='Agrave' convertTo='\`A' />
+  <char num='193' name='Aacute' convertTo='\'A' />
+  <char num='194' name='Acirc' convertTo='\^A' />
+  <char num='195' name='Atilde' convertTo='\~A' />
+
+  <char num='196' name='Auml' convertTo='\"A' />
+  <char num='197' name='Aring' convertTo='\AA' />
+  <char num='198' name='AElig' convertTo='\AE' />
+  <char num='199' name='Ccedil' convertTo='\c{C}' />
+  <char num='200' name='Egrave' convertTo='\`E' />
+  <char num='201' name='Eacute' convertTo='\'E' />
+  <char num='202' name='Ecirc' convertTo='\^E' />
+  <char num='203' name='Euml' convertTo='\"E' />
+  <char num='204' name='Igrave' convertTo='\`I' />
+  <char num='205' name='Iacute' convertTo='\'I' />
+  <char num='206' name='Icirc' convertTo='\^I' />
+  <char num='207' name='Iuml' convertTo='\"I' />
+  <char num='208' name='ETH' convertTo='$\eth$' /> <!-- AMS -->
+  <char num='209' name='Ntilde' convertTo='\~N' />
+  <char num='210' name='Ograve' convertTo='\`O' />
+  <char num='211' name='Oacute' convertTo='\'O' />
+  <char num='212' name='Ocirc' convertTo='\^O' />
+  <char num='213' name='Otilde' convertTo='\~O' />
+  <char num='214' name='Ouml' convertTo='\"O' />
+  <char num='215' name='times' convertTo='$\times$' />
+  <char num='216' name='Oslash' convertTo='\O' />
+  <char num='217' name='Ugrave' convertTo='\`U' />
+  <char num='218' name='Uacute' convertTo='\'U' />
+  <char num='219' name='Ucirc' convertTo='\^U' />
+  <char num='220' name='Uuml' convertTo='\"U' />
+  <char num='221' name='Yacute' convertTo='\'Y' />
+  <char num='223' name='szlig' convertTo='\ss' />
+  <char num='224' name='agrave' convertTo='\`a' />
+  <char num='225' name='aacute' convertTo='\'a' />
+  <char num='226' name='acirc' convertTo='\^a' />
+  <char num='227' name='atilde' convertTo='\~a' />
+  <char num='228' name='auml' convertTo='\"a' />
+  <char num='229' name='aring' convertTo='\aa' />
+  <char num='230' name='aelig' convertTo='\ae' />
+  <char num='231' name='ccedil' convertTo='\c{c}' />
+  <char num='232' name='egrave' convertTo='\`e' />
+  <char num='233' name='eacute' convertTo='\'e' />
+  <char num='234' name='ecirc' convertTo='\^e' />
+  <char num='235' name='euml' convertTo='\"e' />
+  <char num='236' name='igrave' convertTo='\`i' />
+  <char num='237' name='iacute' convertTo='\'i' />
+  <char num='238' name='icirc' convertTo='\^i' />
+  <char num='239' name='iuml' convertTo='\"i' />
+  <char num='240' name='eth' convertTo='$\eth$' package='amssymb'/> <!-- -->
+  <char num='241' name='ntilde' convertTo='\~n' />
+  <char num='242' name='ograve' convertTo='\`o' />
+  <char num='243' name='oacute' convertTo='\'o' />
+  <char num='244' name='ocirc' convertTo='\^o' />
+  <char num='245' name='otilde' convertTo='\~o' />
+  <char num='246' name='ouml' convertTo='\"o' />
+  <!--   <char num='247' name='divide' convertTo='$\divide$' />       -->
+  <char num='248' name='oslash' convertTo='\o' />
+  <char num='249' name='ugrave' convertTo='\`u' />
+  <char num='250' name='uacute' convertTo='\'u' />
+  <char num='251' name='ucirc' convertTo='\^u' />
+  <char num='252' name='uuml' convertTo='\"u' />
+  <char num='253' name='yacute' convertTo='\'y' />
+
+  <char num='255' name='yuml' convertTo='\"y' />
+
+  <char num='222' name='THORN' convertTo='\Thorn' package='wasysym' />
+  <char num='254' name='thorn' convertTo='\thorn' package='wasysym' />
+</chars>
diff --git a/docs/changelog.md b/docs/changelog.md
deleted file mode 100644
index 4b4aec7..0000000
--- a/docs/changelog.md
+++ /dev/null
@@ -1,334 +0,0 @@
-CSS: style.css
-LaTeX CJK: true
-HTML use syntax: true
-
-<!-- #### Changes in the development version (**not yet released**)  ####     {#last} -->
-
-#### Changes in 0.5.6  ####     {#stable}
-
-*	News:
-
-	-	Now Maruku is in the official Gentoo Portage tree (done by [Aggelos Orfanakos])
-	
-*	New stuff: 
-
-	- Attribute `maruku_signature` defaults to false. (many people asked this)
-	- unittests scripts are included in the distribution.
-	- New attribute `filter_html`: if true, raw HTML/XML is discarded. (asked by Marik)
-	- Command line: if output file is `-`, Maruku writes to stdout.
-
-*	Bug fixes:
-
-	*	Another tiny bug in HTML parsing.
-	*	In latex, `\linebreak` was used instead of `\newline` (reported by Sam Kleinman)
-	*	Fixed bug with non-alpha numeric characters in ref.ids (reported by Aggelos Orfanakos)
-
-	
-*	Pending bugs/feature requests:
-
-	- Maruku does not allow 3-space indented lists.
-	- Lists item whose first character is UTF8 are not recognized (reported by Aggelos Orfanakos)
-	- Maruku cannot output `"`-delimited attributes, because `REXML` does not support it.
-	
-[Aggelos Orfanakos]: http://agorf.gr/
-
-#### Changes in 0.5.5  ####    
-
-*	Features:
-
-	*	Input of HTML numeric entities:
-	
-			Examples of numeric character references include © or &#xA9; 
-			for the copyright symbol, Α or &#x391; for the Greek capital 
-			letter alpha, and ا or &#x627; for the Arabic letter alef.
-
-		> Examples of numeric character references include © or &#xA9; 
-		> for the copyright symbol, Α or &#x391; for the Greek capital 
-		> letter alpha, and ا or &#x627; for the Arabic letter alef.
-
-*	Bug fixes:
-	
-	*	Alt text was ignored for images.
-	*	Fixed minor bug in reading HTML inside paragraph.
-	*	Changed rules for block-level HTML to make it similar to Markdown.pl. 
-		For example:
-		
-			Paragraph
-			<div></div>
-		
-		will be translated to 
-
-			<p>Paragraph
-			<div></div></p>
-			
-		while this:
-			
-			Paragraph
-			
-			<div></div>
-		
-		becomes
-		
-			<p>Paragraph</p>
-		
-			<div></div>
-
-*	**Pending bugs**: there are some problems when parsing lists. It is difficult
-	to get it right because the spec is very fuzzy. At the moment, list items 
-	cannot be indented by more than 1 space.
-
-#### Changes in 0.5.4 ####  
-
-*	Features:
-
-	*	[All HTML attributes](http://www.w3.org/TR/html4/index/attributes.html) are supported. 
-	
-			>  Science is a wonderful thing if one does not
-			>  have to earn one's living at it.
-			{: cite="http://en.wikiquote.org/wiki/Albert_Einstein"}
-
-	*	Attribute `doc_prefix`.
-	
-	*	Math:
-		
-		*	`\begin{equation}` and `\end{equation}` are understood.
-		*	Math parsing enabled per-instance using the `math_enabled` attribute.
-		*	`math_numbered` attribute.
-		
-*	Bug fixes:
-
-	*	Runs quietly with `ruby -w`.
-	*	Fixed a bug which could cause data-loss when reading indented lines.
-
-
-#### Changes in 0.5.3 ####  
-
-*	Features:
-
-	*	[All HTML `table` attributes](http://www.w3.org/TR/html4/struct/tables.html#h-11.2.1)
-		can be used (`summary`, `width`, `frame`, `rules`,
-		`border`, `cellspacing`, `cellpadding`).
-		
-		The next version will hopefully use all HTML attributes.
-		
-
-	<!-- A version of Markdown that is more Japanese or something --> 
-	
-*	Bug fixes:
-
-	*	Crash on this line: (found by Aggelos Orfanakos) 
-	
-			[test][]:
-	
-	*	Regression with attribute system (found by Charles)
-
-#### Changes in 0.5.1 ####    
-
-*	Bug fixes:
-	
-	*	Workaround for Internet Explorer bug: 
-		be very sure that `'` is always written as `'`.
-		
-	*	Support for empty images ref: `![image]` and `![image][]`.
-
-	*	Fixed bug in parsing attribute lists definitions.
-
-*	Minor things:
-	
-	*	Now code blocks are written as a `<code>` element inside a `<pre>`, and
-		`<code>` elements have both `class` and `lang` attributes set 
-		to the specified language.
-		
-		Example:
-
-			    Example
-			{:lang=ruby}
-		{:lang=markdown}
-		
-		produces:
-		
-			<pre><code class='ruby' lang='ruby'>Example</code></pre>
-		{:lang=xml}
-		
-#### Changes in 0.5.0 ####  
-
-*	Syntax changes:
-
-	*	Compatibility with newest Markdown.pl: `[text]` as a synonim of `[text][]`.
-
-	*	Meta data: the first IAL in a span environment now refers to the parent.
-		This makes it possible to set attributes for cells:
-
-			Head           |  Head |
-			---------------+-------+--
-			{:r}  Hello    + ...
-
-			{:r: scope='row'}
-
-		The first cell will have the `scope` attribute set to `row`.
-
-*	New settings:
-
-	*	Disable the Maruku signature by setting `maruku signature: false`
-
-*	Stricter doctype. By the way -- did I mention it? -- 
-	**Maruku HTML has always been proper validating XHTML strict** 
-	(if a page does not validate, please report it as a bug).
-
-	Of course, this only matters when using `maruku` as a standalone
-	program.
-
-	*	I have updated the XHTML DTD used to support MathML: 
-		currently using XHTML+MathML+SVG.
-	*	Content-type set to `application/xhtml+xml`	
-	*	All entities are written as numeric entities.
-
-*	Bug fixes
-
-	*	Many fixes in the code handling the sanitizing of inline HTML.
-	*	`markdown=1` did not propagate to children.
-	*	LaTeX: An exception was raised if an unknown entity was used.
-
-#### Changes in 0.4.2 ####    
-
-*	Adapted syntax to the [new meta-data proposal][proposal].
-
-*	Changes in LaTeX export: 
-
-	*	Links to external URLs are blue by default.
-
-	*	New attributes: `latex_preamble` to add a custom preamble,
-		and `latex_cjk` to add packages for UTF-8 Japanese characters.
-		(**support for this is still shaky**). Example:
-	
-			Title: my document
-			LaTeX CJK: true
-			LaTeX preamble: preamble.tex
-		
-			Content
-
-*	Bug fixes
-
-	+ Images were not given `id` or `class` attributes.
-
-	+ Fixed bug in LaTeX export with handling of `<`,`>` enclosed URLs: `<google.com>`.
-
-#### Changes in 0.4.1 aka "Typographer" ####
-
-*	Implemented SmartyPants support:
-
-		'Twas a "test" to 'remember' -- in the '90s 
-		--- while I was <<ok>>. She was 6\"12\'.
-	> 'Twas a "test" to 'remember' -- in the '90s --- while I was <<ok>>.
-	> She was 6\"12\'.
-
-	I adapted the code from RubyPants.
-	
-*	Server directives between `<? ?>` are properly preserved.
-*	Changes in LaTeX export:
-
-	*	Now Japanese text rendering sort of works, using the following packages:
-
-			\usepackage[C40]{fontenc}
-			\usepackage[cjkjis]{ucs}
-			\usepackage[utf8x]{inputenc}
-		
-		Nevertheless, I could only get bitmap fonts working -- probably it's a problem
-		with my setup.
-
-		A quick test: 日本、中国、ひらがな、カタカナ。
-
-	*	Fixed bugs in rendering of immediate links.
-	*	External packages are `require`d only if needed.
-	*	More symbols supported.
-		See the symbol list 
-		[in HTML](http://maruku.rubyforge.org/entity_test.html) and
-		[in PDF](http://maruku.rubyforge.org/entity_test.pdf).
-
-
-#### Changes in 0.4 ####
-
-* First implementation of [the new meta-data syntax][meta].
-* General refactorization of the code and much cleaner error reporting.
-* Created [the RDOC documentation][rdoc].
-* The `add_whitespace` method took too much time -- it was O(n^2).
-* Added unit-tests for block-level elements.
-
-[rdoc]: http://maruku.rubyforge.org/rdoc/
-[meta]: http://maruku.rubyforge.org/proposal.html
-
-
-
-[Jacques Distler]: http://golem.ph.utexas.edu/~distler
-[itex2MML]:  http://golem.ph.utexas.edu/~distler/blog/itex2MML.html
-[math]: http://rubyforge.maruku.org/math.html
-
-
-#### Changes in 0.3 ####
-
-*	A real parser is used instead of a regexp-based system, also for span-level 
-	elements.
-
-	Now Maruku is almost 2x faster than Bluecloth, while having more features.
-
-	Here are some benchmarks:
-	
-		BlueCloth (to_html): parsing 0.00 sec + rendering 1.54 sec = 1.55 sec 
-		Maruku (to_html):    parsing 0.47 sec + rendering 0.38 sec = 0.85 sec 
-		Maruku (to_latex):   parsing 0.49 sec + rendering 0.25 sec = 0.73 sec
-		
-	This is the result of running `lib/maruku/tests/benchmark.rb` on the Markdown 
-	specification.
-
-*	Prettier HTML output by adding whitespace.
- 
-*	Added a full suite of unit-tests for the span-level parser.
-
-*	Error management: Having a real parser, Maruku warns you about syntax issues.
-	
-	The default action is to warn and try to continue. If you do this:
-
-		Maruku.new(string, {:on_error => :raise})
-
-	then syntax errors will cause an exception to be raised (you can catch this
-	and retry).
-
-*	Fixed a series of bugs in handling inline HTML code.
-
-Immediate TODO-list:
-
-*	UTF-8 input/output works OK for HTML, however I am having pain trying to export
-	to LaTeX. I want at least Japanese characters support, so if you know how to 
-	do this you are very welcome to give me an hand.
-	
-	For example: in the HTML version, you should see accented characters in this
-	parenthesis: 
-	
-	> (àèìòù)
-	
-	and Japanese text in these other parentheses: 
-	
-	> (カタカナで 私の 名前は アンドレア チェンシ です).
-	>
-	> (日本のガルは 大好き、でも、日本語は難しですから、そうぞ 英語話すガルを おしえてください).
-	
-	In the LaTeX version, these do not appear. I know how to do LaTeX with 
-	ISO-8859-1 encoding (European characters), but I'm struggling with half-baked 
-	solutions for UTF-8 encoded documents.
-
-*	Implement the [new meta-data proposal][proposal].
-
-*	Exporting to Markdown (pretty printing).
-
-*	Exporting to HTML splitting in multiple files.
-
-*	RubyPants.
-
-*	Support for images in PDF.
-
-
-[proposal]: http://maruku.rubyforge.org/proposal.html
-[contact]: http://www.dis.uniroma1.it/~acensi/contact.html
-[markdown-discuss]: http://six.pairlist.net/mailman/listinfo/markdown-discuss
-[tracker]: http://rubyforge.org/tracker/?group_id=2795
-
diff --git a/docs/markdown_syntax.md b/docs/markdown_syntax.md
index b8b2a4d..9a40124 100644
--- a/docs/markdown_syntax.md
+++ b/docs/markdown_syntax.md
@@ -1,17 +1,6 @@
-css: style.css
-
 Markdown: Syntax
 ================
 
-<ul id="ProjectSubmenu">
-    <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
-    <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
-    <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
-    <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
-    <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
-</ul>
-
-
 *   [Overview](#overview)
     *   [Philosophy](#philosophy)
     *   [Inline HTML](#html)
@@ -256,7 +245,7 @@ wrap the text and put a `>` before every line:
     > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
     > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
     > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
-    > 
+    >
     > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
     > id sem consectetuer libero luctus adipiscing.
 
@@ -283,12 +272,12 @@ Blockquotes can contain other Markdown elements, including headers, lists,
 and code blocks:
 
 	> ## This is a header.
-	> 
+	>
 	> 1.   This is the first list item.
 	> 2.   This is the second list item.
-	> 
+	>
 	> Here's some example code:
-	> 
+	>
 	>     return shell_exec("echo $input | $markdown_script");
 
 Any decent text editor should make email-style quoting easy. For
@@ -569,7 +558,7 @@ Will produce:
 If you're referring to a local resource on the same server, you can
 use relative paths:
 
-    See my [About](/about/) page for details.   
+    See my [About](/about/) page for details.
 
 Reference-style links use a second set of square brackets, inside
 which you place a label of your choosing to identify the link:
@@ -643,7 +632,7 @@ multiple words in the link text:
 	Visit [Daring Fireball][] for more information.
 
 And then define the link:
-	
+
 	[Daring Fireball]: http://daringfireball.net/
 
 Link definitions can be placed anywhere in your Markdown document. I
@@ -767,13 +756,13 @@ one after the opening, one before the closing. This allows you to place
 literal backtick characters at the beginning or end of a code span:
 
 	A single backtick in a code span: `` ` ``
-	
+
 	A backtick-delimited string in a code span: `` `foo` ``
 
 will produce:
 
 	<p>A single backtick in a code span: <code>`</code></p>
-	
+
 	<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
 
 With a code span, ampersands and angle brackets are encoded as HTML
@@ -844,7 +833,7 @@ use regular HTML `<img>` tags.
 Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
 
     <http://example.com/>
-    
+
 Markdown will turn this into:
 
     <a href="http://example.com/">http://example.com/</a>
@@ -896,4 +885,3 @@ Markdown provides backslash escapes for the following characters:
 	-	minus sign (hyphen)
     .   dot
     !   exclamation mark
-
diff --git a/docs/math.md b/docs/math.md
index 16bed4a..976eb96 100644
--- a/docs/math.md
+++ b/docs/math.md
@@ -9,11 +9,7 @@ Math support in Maruku
 
 This document describes Maruku's support of inline LaTeX-style math.
 
-At the moment, **these features are experimental**, are probably
-buggy and the syntax and implementation are bound to change in
-the near future.
-
-Also, there are many subtleties of which one must care for 
+There are many subtleties of which one must care for 
 correctly serving the XHTML+MathML document to browsers.
 In fact, *this documentation is __not__ enough to get you started*, 
 unless you feel very adventurous.
@@ -118,7 +114,7 @@ You have to enable the math extension like this:
 
 Use the following to choose the engine:
 
-	MaRuKu::Globals[:html_math_engine] = 'ritex'
+	MaRuKu::Globals[:html_math_engine] = 'itex2mml'
 	MaRuKu::Globals[:html_png_engine] =  'blahtex'
 	
 Available MathML engines are 'none', 'itex2mml', 'blahtex'.
@@ -129,21 +125,13 @@ External libraries needed
 
 To output MathML or PNGs, it is needed to install one of the following libraries
 
-### Using `ritex` ### {#using_ritex}
-
-Install with 
-
-	$ gem install ritex
-
-ritex's abilities are very limited, but it is the easiest to install.
-
 ### Using `itex2mml` ### {#using_itex2mml}
 
 itex2mml supports much more LaTeX commands/environments than ritex.
 
-Install itex2mml using the instructions at:
+Install itextomml with 
 
-> <http://golem.ph.utexas.edu/~distler/blog/itex2MML.html> 
+	$ gem install itextomml
 
 This is a summary of the available LaTeX commands:
 
@@ -152,10 +140,18 @@ This is a summary of the available LaTeX commands:
 Moreover, [Jacques Distler] is integrating Maruku+itex2mml+[Instiki].
 You can find more information here:
 
-> <http://golem.ph.utexas.edu/~distler/blog/archives/001111.html>
+> <http://golem.ph.utexas.edu/wiki/instiki/show/HomePage>
 
 [Jacques Distler]: http://golem.ph.utexas.edu/~distler
-[instiki]: http://www.instiki.org
+[instiki]: http://golem.ph.utexas.edu/wiki/instiki/show/HomePage
+
+### Using `ritex` ### {#using_ritex}
+
+Install with 
+
+	$ gem install ritex
+
+ritex's abilities are very limited, but it is the easiest to install since, unlike `itextomml`, it is a pure-ruby implementation.
 
 ### Using `blahtex` ### {#using_blahtex}
 
diff --git a/lib/maruku.rb b/lib/maruku.rb
index 71d5aa4..2038374 100644
--- a/lib/maruku.rb
+++ b/lib/maruku.rb
@@ -1,83 +1,74 @@
 #--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
+# Copyright (c) 2006 Andrea Censi
 #
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #++
 
-require 'rexml/document'
-
-# :include:MaRuKu.txt
 module MaRuKu
-
-	module In
-		module Markdown
-			module SpanLevelParser; end
-			module BlockLevelParser; end
-		end
-		# more to come?
-	end
-
-	module Out
-		# Functions for exporting to MarkDown.
-		module Markdown; end
-		# Functions for exporting to HTML.
-		module HTML; end
-		# Functions for exporting to Latex
-		module Latex; end
-	end
-		
-	# These are strings utilities.
-	module Strings; end
-
-	module Helpers; end
-
-	module Errors; end
-		
-	class MDElement
-		include REXML
-		include MaRuKu
-		include Out::Markdown
-		include Out::HTML
-		include Out::Latex
-		include Strings
-		include Helpers
-		include Errors
-	end
-	
-	
-	class MDDocument < MDElement
-		include In::Markdown
-		include In::Markdown::SpanLevelParser
-		include In::Markdown::BlockLevelParser
-	end
+  module In
+    module Markdown
+      module SpanLevelParser; end
+      module BlockLevelParser; end
+    end
+  end
+
+  module Out
+    module Markdown; end
+    module HTML; end
+    module Latex; end
+  end
+
+  module Strings; end
+
+  module Helpers; end
+
+  module Errors; end
+
+  class MDElement
+    include MaRuKu
+    include Out::Markdown
+    include Out::HTML
+    include Out::Latex
+    include Strings
+    include Helpers
+    include Errors
+  end
+
+  class MDDocument < MDElement
+    include In::Markdown
+    include In::Markdown::SpanLevelParser
+    include In::Markdown::BlockLevelParser
+  end
 end
 
-# This is the public interface
 class Maruku < MaRuKu::MDDocument; end
 
 
-
-require 'rexml/document'
-
 # Structures definition
-require 'maruku/structures'
-require 'maruku/structures_inspect'
+require 'maruku/attributes'
+require 'maruku/element'
+require 'maruku/document'
+require 'maruku/inspect_element'
 
 require 'maruku/defaults'
+
 # Less typing
 require 'maruku/helpers'
 
@@ -87,7 +78,7 @@ require 'maruku/input/parse_doc'
 # Ugly things kept in a closet
 require 'maruku/string_utils'
 require 'maruku/input/linesource'
-require 'maruku/input/type_detection'
+require 'maruku/input/mdline'
 
 # A class for reading and sanitizing inline HTML
 require 'maruku/input/html_helper'
@@ -97,34 +88,32 @@ require 'maruku/input/parse_block'
 
 # Code for parsing Markdown span-level elements
 require 'maruku/input/charsource'
-require 'maruku/input/parse_span_better'
+require 'maruku/input/parse_span'
 require 'maruku/input/rubypants'
 
 require 'maruku/input/extensions'
 
-require 'maruku/attributes'
-
-require 'maruku/structures_iterators'
-
-require 'maruku/errors_management'
+require 'maruku/errors'
 
 # Code for creating a table of contents
 require 'maruku/toc'
 
 # Support for div Markdown extension
 require 'maruku/ext/div'
+# Support for fenced codeblocks extension
+require 'maruku/ext/fenced_code'
 
 # Version and URL
 require 'maruku/version'
 
+# Entity conversion for HTML and LaTeX
+require 'maruku/output/entity_table'
 
 # Exporting to html
 require 'maruku/output/to_html'
 
 # Exporting to latex
 require 'maruku/output/to_latex'
-require 'maruku/output/to_latex_strings'
-require 'maruku/output/to_latex_entities'
 
 # Pretty print
 require 'maruku/output/to_markdown'
@@ -138,4 +127,3 @@ require 'maruku/output/to_s'
 
 # class Maruku is the global interface
 require 'maruku/maruku'
-
diff --git a/lib/maruku/attributes.rb b/lib/maruku/attributes.rb
index 74d7fe9..93a4730 100644
--- a/lib/maruku/attributes.rb
+++ b/lib/maruku/attributes.rb
@@ -1,227 +1,122 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
+module MaRuKu
+  # This represents a list of attributes specified in the Markdown document
+  # that apply to a Markdown-generated tag.
+  # What was `{#id .class key="val" ref}` in the Markdown
+  # is parsed into `[[:id, 'id'], [:class, 'class'], ['key', 'val'], [:ref, 'ref']]`.
+  class AttributeList < Array
+    def to_s
+      map do |k, v|
+        value = quote_if_needed(v)
+        case k
+        when :id;    "#" + value
+        when :class; "." + value
+        when :ref;    value
+        else quote_if_needed(k) + "=" + value
+        end
+      end.join(' ')
+    end
+    alias to_md to_s
 
+    private
 
-class String
-	def quote_if_needed
-		if /[\s\'\"]/.match self
-			inspect
-		else
-			self
-		end
-	end
-end
-
-module MaRuKu; 
-	MagicChar = ':'
-	
-	class AttributeList < Array
-		
-		# An attribute list becomes 
-		# {#id .cl key="val" ref}
-		# [ [:id, 'id'], [:class, 'id'], ['key', 'val'], [ :ref, 'ref' ]]
+    def quote_if_needed(str)
+      (str =~ /[\s'"]/) ? str.inspect : str
+    end
+  end
 
-		private :push
-		
-		def push_key_val(key, val); 
-			raise "Bad #{key.inspect}=#{val.inspect}" if not key and val
-			push [key, val] 
-		end
-		def push_ref(ref_id);       
-			
-			raise "Bad :ref #{ref_id.inspect}" if not ref_id
-			push [:ref, ref_id+""] 
+  module In::Markdown::SpanLevelParser
+    def md_al(s = [])
+      AttributeList.new(s)
+    end
 
-#			p "Now ", self ########################################
-		end
-		def push_class(val);        
-			raise "Bad :id #{val.inspect}" if not val
-			push [:class,  val] 
-		end
-		def push_id(val);           
-			raise "Bad :id #{val.inspect}" if not val
-			push [:id,  val] 
-		end
-		
-		def to_s
-			map do |k,v|
-				case k
-				when :id;    "#" + v.quote_if_needed
-				when :class; "." + v.quote_if_needed
-				when :ref;    v.quote_if_needed
-				else k.quote_if_needed + "=" + v.quote_if_needed
-				end
-			end . join(' ')
-		end
-		alias to_md to_s 
-	end
-	
-end
+    # @return [AttributeList, nil]
+    def read_attribute_list(src, con=nil, break_on_chars=nil)
+      break_on_chars = Array(break_on_chars)
+      separators = break_on_chars + ['=', ' ', "\t"]
+      escaped = Maruku::EscapedCharInQuotes
 
-module MaRuKu; module In; module Markdown; module SpanLevelParser
-	
-	def unit_tests_for_attribute_lists
-		[
-			[ "",     [], "Empty lists are allowed" ], 
-			[ "=",    :throw, "Bad char to begin a list with." ], 
-			[ "a =b", :throw, "No whitespace before `=`." ], 
-			[ "a= b", :throw, "No whitespace after `=`." ], 
+      al = AttributeList.new
+      loop do
+        src.consume_whitespace
+        break if break_on_chars.include? src.cur_char
 
-			[ "a b", [[:ref, 'a'],[:ref, 'b']], "More than one ref" ], 
-			[ "a b c", [[:ref, 'a'],[:ref, 'b'],[:ref, 'c']], "More than one ref" ], 
-			[ "hello notfound", [[:ref, 'hello'],[:ref, 'notfound']]], 
+        case src.cur_char
+        when ':'
+          src.ignore_char
+        when nil
+          break      # we're done here.
+        when '='     # error
+          src.ignore_char
+          maruku_error "In attribute lists, cannot start identifier with `=`."
+          tell_user "Ignoring and continuing."
+        when '#'     # id definition
+          src.ignore_char
+          if id = read_quoted_or_unquoted(src, con, escaped, separators)
+            al << [:id, id]
+          else
+            maruku_error 'Could not read `id` attribute.', src, con
+            tell_user 'Ignoring bad `id` attribute.'
+          end
+        when '.'     # class definition
+          src.ignore_char
+          if klass = read_quoted_or_unquoted(src, con, escaped, separators)
+            al << [:class, klass]
+          else
+            maruku_error 'Could not read `class` attribute.', src, con
+            tell_user 'Ignoring bad `class` attribute.'
+          end
+        else
+          unless key = read_quoted_or_unquoted(src, con, escaped, separators)
+            maruku_error 'Could not read key or reference.'
+            next
+          end
 
-			[ "'a'",  [[:ref, 'a']], "Quoted value." ], 
-			[ '"a"'   ], 
+          if src.cur_char != '=' && key.length > 0
+            al << [:ref, key]
+            next
+          end
 
-			[ "a=b",  [['a','b']], "Simple key/val" ], 
-			[ "'a'=b"   ], 
-			[ "'a'='b'" ], 
-			[ "a='b'"   ], 
+          src.ignore_char # skip the =
+          if val = read_quoted_or_unquoted(src, con, escaped, separators)
+            al << [key, val]
+          else
+            maruku_error "Could not read value for key #{key.inspect}.", src, con
+            tell_user "Ignoring key #{key.inspect}"
+          end
+        end
+      end
+      al
+    end
 
-			[ 'a="b\'"',  [['a',"b\'"]], "Key/val with quotes" ],
-			[ 'a=b\''],
-			[ 'a="\\\'b\'"',  [['a',"\'b\'"]], "Key/val with quotes" ], 
-			
-			['"', :throw, "Unclosed quotes"],
-			["'"],
-			["'a "],
-			['"a '],
-			
-			[ "#a",  [[:id, 'a']], "Simple ID" ], 
-			[ "#'a'" ], 
-			[ '#"a"' ], 
+    def merge_ial(elements, src, con)
+      # Apply each IAL to the element before
+      (elements + [nil]).each_cons(3) do |before, e, after|
+        next unless ial?(e)
 
-			[ "#",  :throw, "Unfinished '#'." ], 
-			[ ".",  :throw, "Unfinished '.'." ], 
-			[ "# a",  :throw, "No white-space after '#'." ], 
-			[ ". a",  :throw, "No white-space after '.' ." ], 
-			
-			[ "a=b c=d",  [['a','b'],['c','d']], "Tabbing" ], 
-			[ " \ta=b \tc='d' "],
-			[ "\t a=b\t c='d'\t\t"],
-			
-			[ ".\"a'",  :throw, "Mixing quotes is bad." ], 
-			
-		].map { |s, expected, comment| 
-			@expected = (expected ||= @expected)
-			@comment  = (comment  ||= (last=@comment) )
-			(comment == last && (comment += (@count+=1).to_s)) || @count = 1
-			expected = [md_ial(expected)] if expected.kind_of? Array
-			["{#{MagicChar}#{s}}", expected, "Attributes: #{comment}"]
-		}
-	end
-	
-	def md_al(s=[]); AttributeList.new(s) end
+        if before.kind_of? MDElement
+          before.al = e.ial
+        elsif after.kind_of? MDElement
+          after.al = e.ial
+        else
+          maruku_error <<ERR, src, con
+It's unclear which element the attribute list {:#{e.ial.to_s}}
+is referring to. The element before is a #{before.class},
+the element after is a #{after.class}.
+  before: #{before.inspect}
+  after: #{after.inspect}
+ERR
+        end
+      end
 
-	# returns nil or an AttributeList
-	def read_attribute_list(src, con, break_on_chars)
-		
-		separators = break_on_chars + [?=,?\ ,?\t]
-		escaped = Maruku::EscapedCharInQuotes
-			
-		al = AttributeList.new
-		while true
-			src.consume_whitespace
-			break if break_on_chars.include? src.cur_char
-	
-			case src.cur_char
-			when nil 
-				maruku_error "Attribute list terminated by EOF:\n "+
-				             "#{al.inspect}" , src, con
-				tell_user "I try to continue and return partial attribute list:\n"+
-					al.inspect
-				break
-			when ?=     # error
-				maruku_error "In attribute lists, cannot start identifier with `=`."
-				tell_user "I try to continue"
-				src.ignore_char
-			when ?#     # id definition
-				src.ignore_char
-				if id = read_quoted_or_unquoted(src, con, escaped, separators)
-					al.push_id id
-				else
-					maruku_error 'Could not read `id` attribute.', src, con
-					tell_user 'Trying to ignore bad `id` attribute.'
-				end
-			when ?.     # class definition
-				src.ignore_char
-				if klass = read_quoted_or_unquoted(src, con, escaped, separators)
-					al.push_class klass
-				else
-					maruku_error 'Could not read `class` attribute.', src, con
-					tell_user 'Trying to ignore bad `class` attribute.'
-				end
-			else
-				if key = read_quoted_or_unquoted(src, con, escaped, separators)
-					if src.cur_char == ?=
-						src.ignore_char # skip the =
-						if val = read_quoted_or_unquoted(src, con, escaped, separators)
-							al.push_key_val(key, val)
-						else
-							maruku_error "Could not read value for key #{key.inspect}.",
-								src, con
-							tell_user "Ignoring key #{key.inspect}."
-						end
-					else
-						al.push_ref key
-					end
-				else
-					maruku_error 'Could not read key or reference.'
-				end
-			end # case
-		end # while true
-		al
-	end
-	
-	
-	# We need a helper
-	def is_ial(e); e.kind_of? MDElement and e.node_type == :ial end
+      unless Globals[:debug_keep_ials]
+        elements.delete_if {|x| ial?(x) && x != elements.first}
+      end
+    end
 
-	def merge_ial(elements, src, con)	
+    private
 
-		# Apply each IAL to the element before
-		elements.each_with_index do |e, i| 
-		if is_ial(e) && i>= 1 then
-			before = elements[i-1]
-			after = elements[i+1]
-			if before.kind_of? MDElement
-				before.al = e.ial
-			elsif after.kind_of? MDElement
-				after.al = e.ial
-			else
-				maruku_error "It is not clear to me what element this IAL {:#{e.ial.to_md}} \n"+
-				"is referring to. The element before is a #{before.class.to_s}, \n"+
-				"the element after is a #{after.class.to_s}.\n"+
-				"\n before: #{before.inspect}"+
-				"\n after: #{after.inspect}",
-				src, con
-				# xxx dire se c'è empty vicino
-			end
-		end 
-		end
-		
-		if not Globals[:debug_keep_ials]
-			elements.delete_if {|x| is_ial(x) unless x == elements.first} 
-		end
-	end
-		
-end end end end 
-#module MaRuKu; module In; module Markdown; module SpanLevelParser
+    def ial?(e)
+      e.is_a?(MDElement) && e.node_type == :ial
+    end
+  end
+end
diff --git a/lib/maruku/defaults.rb b/lib/maruku/defaults.rb
index ea4a328..e72394a 100644
--- a/lib/maruku/defaults.rb
+++ b/lib/maruku/defaults.rb
@@ -1,71 +1,49 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
+module MaRuKu
 
+  Globals = {
+    :unsafe_features => false,
+    :on_error => :warning,
 
-module MaRuKu
-	
-Globals = {
-	:unsafe_features => false,
-	:on_error => :warning,
-	
-	
-	:use_numbered_headers => false,
-	
-	:maruku_signature => false,
-	:code_background_color => '#fef',
-	:code_show_spaces => false,
-	
-	:filter_html => false,
-	
-	:html_math_output_mathml => true, # also set :html_math_engine
-	:html_math_engine => 'none', #ritex, itex2mml
-	
-	:html_math_output_png => false, 	
-	:html_png_engine => 'none',
-	:html_png_dir => 'pngs',
-	:html_png_url => 'pngs/',
-	:html_png_resolution => 200,
-  
-	:html_use_syntax => false,
-	
-	:latex_use_listings => false,
-	:latex_cjk => false,
-  :latex_cache_file  => "blahtex_cache.pstore", # cache file for blahtex filter
-	
-	:debug_keep_ials => false,
-	:doc_prefix => ''
-}
+    :use_numbered_headers => false,
 
-class MDElement
-	def get_setting(sym)
-		if self.attributes.has_key?(sym) then
-			return self.attributes[sym]
-		elsif self.doc && self.doc.attributes.has_key?(sym) then
-			return self.doc.attributes[sym]
-		elsif MaRuKu::Globals.has_key?(sym)
-			return MaRuKu::Globals[sym]
-		else
-			$stderr.puts "Bug: no default for #{sym.inspect}"
-			nil
-		end
-	end
-end
+    :maruku_signature => false,
+    :code_background_color => '#fef',
+    :code_show_spaces => false,
+
+    :filter_html => false,
+
+    :html_parser => 'rexml', # or 'nokogiri'
+
+    :html_math_output_mathml => true, # also set :html_math_engine
+    :html_math_engine => 'none', # none, ritex, itex2mml, blahtex
+
+    :html_math_output_png => false,
+    :html_png_engine => 'none',
+    :html_png_dir => 'pngs',
+    :html_png_url => 'pngs/',
+    :html_png_resolution => 200,
 
-end
\ No newline at end of file
+    :fenced_code_blocks => false,
+    :html_use_syntax => false,
+
+    :latex_use_listings => false,
+    :latex_cjk => false,
+
+    :debug_keep_ials => false,
+    :doc_prefix => '',
+
+    :ignore_wikilinks => true
+  }
+
+  class MDElement
+    def get_setting(sym)
+      return attributes[sym] if attributes.has_key?(sym)
+      return doc.attributes[sym] if doc && doc.attributes.has_key?(sym)
+      return MaRuKu::Globals[sym] if MaRuKu::Globals.has_key?(sym)
+
+      $stderr.puts "Bug: no default for #{sym.inspect}"
+      nil
+    end
+  end
+
+end
diff --git a/lib/maruku/document.rb b/lib/maruku/document.rb
new file mode 100644
index 0000000..3b63c67
--- /dev/null
+++ b/lib/maruku/document.rb
@@ -0,0 +1,43 @@
+module MaRuKu
+  # This represents the whole document and holds global data.
+  class MDDocument # < MDElement
+    # @return [{String => {:url => String, :title => String}}]
+    attr_accessor :refs
+
+    # @return [{String => MDElement}]
+    attr_accessor :footnotes
+
+    # @return [{String => String}]
+    attr_accessor :abbreviations
+
+    # Attribute definition lists.
+    #
+    # @return [{String => AttributeList}]
+    attr_accessor :ald
+
+    # The order in which footnotes are used. Contains the id.
+    #
+    # @return [Array<String>]
+    attr_accessor :footnotes_order
+
+    # @return [{String => {String => MDElement}}]
+    attr_accessor :refid2ref
+
+    # A counter for generating unique IDs [Integer]
+    attr_accessor :id_counter
+
+    def initialize(s=nil)
+      super(:document)
+
+      self.doc = self
+      self.refs = {}
+      self.footnotes = {}
+      self.footnotes_order = []
+      self.abbreviations = {}
+      self.ald = {}
+      self.id_counter = 0
+
+      parse_doc(s) if s
+    end
+  end
+end
diff --git a/lib/maruku/element.rb b/lib/maruku/element.rb
new file mode 100644
index 0000000..64991fd
--- /dev/null
+++ b/lib/maruku/element.rb
@@ -0,0 +1,127 @@
+module MaRuKu
+  # Rather than having a separate class for every possible element,
+  # Maruku has a single {MDElement} class
+  # that represents eveything in the document (paragraphs, headers, etc).
+  # The type of each element is available via \{#node\_type}.
+  class MDElement
+    # The type of this node (e.g. `:quote`, `:image`, `:abbr`).
+    # See {Helpers} for a list of possible values.
+    #
+    # @return [Symbol]
+    attr_accessor :node_type
+
+    # The child nodes of this element.
+    #
+    # @return [Array<String or MDElement>]
+    attr_accessor :children
+
+    # An attribute list. May not be nil.
+    #
+    # @return [AttributeList]
+    attr_accessor :al
+
+    # The processed attributes.
+    #
+    # For the {Maruku document root},
+    # this contains properties listed
+    # at the beginning of the document.
+    # The properties will be downcased and any spaces
+    # will be converted to underscores.
+    # For example, if you write in the source document:
+    #
+    #     !!!text
+    #     Title: test document
+    #     My property: value
+    #
+    #     content content
+    #
+    # Then \{#attributes} will return:
+    #
+    #     {:title => "test document", :my_property => "value"}
+    #
+    # @return [{Symbol => String}]
+    attr_accessor :attributes
+
+    # The root element of the document
+    # to which this element belongs.
+    #
+    # @return [Maruku]
+    attr_accessor :doc
+
+    def initialize(node_type = :unset, children = [], meta = {}, al = nil)
+      self.children = children
+      self.node_type = node_type
+      self.attributes = {}
+
+      # Define a new accessor on the singleton class for this instance
+      # for each metadata key
+      meta.each do |symbol, value|
+        class << self
+          self
+        end.send(:attr_accessor, symbol)
+
+        self.send("#{symbol}=", value)
+      end
+
+      self.al = al || AttributeList.new
+      self.meta_priv = meta
+    end
+
+    # @private
+    attr_accessor :meta_priv
+
+    def ==(o)
+      o.is_a?(MDElement) &&
+        self.node_type == o.node_type &&
+        self.meta_priv == o.meta_priv &&
+        self.children == o.children
+    end
+
+    # Iterates through each {MDElement} child node of this element.
+    # This includes deeply-nested child nodes.
+    # If `e_node_type` is specified, only yields nodes of that type.
+    def each_element(e_node_type=nil, &block)
+      @children.each do |c|
+        if c.is_a? MDElement then
+          yield c if e_node_type.nil? || c.node_type == e_node_type
+          c.each_element(e_node_type, &block)
+        #
+        # This handles the case where the children of an
+        # element are arranged in a multi-dimensional array
+        # (as in the case of a table)
+        elsif c.is_a? Array then
+          c.each do |cc|
+            # A recursive call to each_element will ignore the current element
+            # so we handle this case inline
+            if cc.is_a? MDElement then
+              yield cc if e_node_type.nil? || cc.node_type == e_node_type
+              cc.each_element(e_node_type, &block)
+            end
+          end
+        end
+
+      end
+    end
+
+    # Iterates through each String child node of this element,
+    # replacing it with the result of the block.
+    # This includes deeply-nested child nodes.
+    #
+    # This destructively modifies this node and its children.
+    #
+    # @todo Make this non-destructive
+    def replace_each_string(&block)
+      @children.map! do |c|
+        next yield c unless c.is_a?(MDElement)
+        c.replace_each_string(&block)
+        c
+      end.flatten!
+    end
+  end
+
+  # A specialization of Element that can keep track of
+  # its parsed HTML as an attribute (rather than metadata)
+  class MDHTMLElement < MDElement
+    attr_accessor :parsed_html # HTMLFragment
+  end
+end
diff --git a/lib/maruku/errors.rb b/lib/maruku/errors.rb
new file mode 100644
index 0000000..fbdc2a7
--- /dev/null
+++ b/lib/maruku/errors.rb
@@ -0,0 +1,71 @@
+module MaRuKu
+  class Exception < RuntimeError; end
+
+  module Errors
+    FRAME_WIDTH = 75
+
+    # Properly handles a formatting error.
+    # All such errors go through this method.
+    #
+    # The behavior depends on {MaRuKu::Globals `MaRuKu::Globals[:on_error]`}.
+    # If this is `:warning`, this prints the error to stderr
+    # (or `@error_stream` if it's defined) and tries to continue.
+    # If `:on_error` is `:ignore`, this doesn't print anything
+    # and tries to continue. If it's `:raise`, this raises a {MaRuKu::Exception}.
+    #
+    # By default, `:on_error` is set to `:warning`.
+    #
+    # @overload def maruku_error(s, src = nil, con = nil)
+    # @param s [String] The text of the error
+    # @param src [#describe, nil] The source of the error
+    # @param con [#describe, nil] The context of the error
+    # @param recover [String, nil] Recovery text
+    # @raise [MaRuKu::Exception] If `:on_error` is set to `:raise`
+    def maruku_error(s, src=nil, con=nil, recover=nil)
+      policy = get_setting(:on_error)
+
+      case policy
+      when :ignore
+      when :raise
+        raise_error create_frame(describe_error(s, src, con, recover))
+      when :warning
+        tell_user create_frame(describe_error(s, src, con, recover))
+      else
+        raise "Unknown on_error policy: #{policy.inspect}"
+      end
+    end
+
+    def maruku_recover(s, src=nil, con=nil, recover=nil)
+      tell_user create_frame(describe_error(s, src, con, recover))
+    end
+
+    def raise_error(s)
+      raise MaRuKu::Exception, s, caller
+    end
+
+    def tell_user(s)
+      (self.attributes[:error_stream] || $stderr) << s << "\n"
+    end
+
+    private
+
+    def create_frame(s)
+      "\n" + <<FRAME
+ #{"_" * FRAME_WIDTH}
+| Maruku tells you:
++#{"-" * FRAME_WIDTH}
+#{s.gsub(/^/, '| ').rstrip}
++#{"-" * FRAME_WIDTH}
+#{caller[1...5].join("\n").gsub(/^/, '!')}
+\\#{"_" * FRAME_WIDTH}
+FRAME
+    end
+
+    def describe_error(s, src=nil, con=nil, recover=nil)
+      s += "\n#{src.describe}\n" if src
+      s += "\n#{con.describe}\n" if con
+      s += "\nRecovering: #{recover}\n" if recover
+      s
+    end
+  end
+end
diff --git a/lib/maruku/errors_management.rb b/lib/maruku/errors_management.rb
deleted file mode 100644
index 9aa8d3b..0000000
--- a/lib/maruku/errors_management.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-
-#m  Any method that detects formatting error calls the
-#m  maruku_error() method. 
-#m  if @meta[:on_error] == 
-#m
-#m  - :warning   write on the standard err (or @error_stream if defined), 
-#m              then do your best.
-#m  - :ignore    be shy and try to continue
-#m  - :raise     raises a MarukuException
-#m
-#m  default is :raise
-
-module MaRuKu
-	
-	class Exception < RuntimeError
-	end
-	
-module Errors
-	
-	def maruku_error(s,src=nil,con=nil)
-		policy = get_setting(:on_error)
-		
-		case policy
-		when :ignore 
-		when :raise
-			raise_error create_frame(describe_error(s,src,con))
-		when :warning
-			tell_user create_frame(describe_error(s,src,con))
-		else
-			raise "BugBug: policy = #{policy.inspect}"
-		end
-	end
-	
-	def maruku_recover(s,src=nil,con=nil)
-		tell_user create_frame(describe_error(s,src,con))
-	end
-	
-	alias error maruku_error
-
-	def raise_error(s)
-		raise MaRuKu::Exception, s, caller
-	end
-
-	def tell_user(s)
-		error_stream = self.attributes[:error_stream] || $stderr
-		error_stream << s 
-	end
-	
-	def create_frame(s)
-		n = 75
-		"\n" +
-		" "+"_"*n + "\n"+
-		"| Maruku tells you:\n" +
-		"+" + ("-"*n) +"\n"+
-		add_tabs(s,1,'| ') + "\n" +
-		"+" + ("-"*n) + "\n" +
-		add_tabs(caller[0, 5].join("\n"),1,'!') + "\n" +
-		"\\" + ("_"*n) + "\n"
-	end
-
-	def describe_error(s,src,con)
-		t = s
-		src && (t += "\n#{src.describe}\n")
-		con && (t += "\n#{con.describe}\n")
-		t
-	end
-	
-end # Errors
-end # MaRuKu
-
-
diff --git a/lib/maruku/ext/div.rb b/lib/maruku/ext/div.rb
index 87f4d2f..ada569d 100644
--- a/lib/maruku/ext/div.rb
+++ b/lib/maruku/ext/div.rb
@@ -1,5 +1,3 @@
-
-
 #+-----------------------------------{.warning}------
 #| this is the last warning!
 #|
@@ -10,124 +8,118 @@
 #| +--------------------------------------------------
 #+---------------------------------------------------
 
-OpenDiv = /^[ ]{0,3}\+\-\-+\s*(\{([^{}]*|".*"|'.*')*\})?\s*\-*\s*$/
-CloseDiv = /^[ ]{0,3}\=\-\-+\s*(\{([^{}]*|".*"|'.*')*\})?\s*\-*\s*$/
-# note these are not enough for parsing the above example:
-#OpenDiv = /^[ ]{0,3}\+\-\-+\s*(.*)$/
-#CloseDiv = /^[ ]{0,3}\=\-\-+\s*(.*)$/
+# TODO: Scope these properly
+OpenDiv = /^[ ]{0,3}\+\-\-+\s*(\{([^{}]*?|".*?"|'.*?')*\})?\s*\-*\s*$/
+CloseDiv = /^[ ]{0,3}\=\-\-+\s*(\{([^{}]*?|".*?"|'.*?')*\})?\s*\-*\s*$/
 StartPipe = /^[ ]{0,3}\|(.*)$/ # $1 is rest of line
 DecorativeClosing = OpenDiv
 
-MaRuKu::In::Markdown::register_block_extension(
-	:regexp  => OpenDiv,
-	:handler => lambda { |doc, src, context|
-		# return false if not doc.is_math_enabled?
-		first = src.shift_line
-		first =~ OpenDiv
-		ial_at_beginning = $1
-		ial_at_end = nil
-		
-		lines = []
-		# if second line starts with "|"
-		if src.cur_line =~ StartPipe
-			# then we read until no more "|"
-			while src.cur_line && (src.cur_line =~ StartPipe)
-				content = $1
-				lines.push content
-				src.shift_line
-			end
-			if src.cur_line =~ DecorativeClosing
-				ial_at_end = $1
-				src.shift_line 
-			end
-		else
-			# else we read until CloseDiv
-			divs_open = 1
-			while src.cur_line && (divs_open>0)
-				if src.cur_line =~ CloseDiv
-					divs_open -= 1
-					if divs_open == 0
-						ial_at_end = $1
-						src.shift_line
-						break
-					else
-						lines.push src.shift_line
-					end
-				else
-					if src.cur_line =~ OpenDiv
-						divs_open += 1 
-					end
-					lines.push src.shift_line
-				end
-			end
-			
-			if divs_open > 0
-				e = "At end of input, I still have #{divs_open} DIVs open."
-				doc.maruku_error(e, src, context)
-				return true
-			end
-		end
-		
-		ial_at_beginning = nil unless 
-			(ial_at_beginning&&ial_at_beginning.size > 0)
-		ial_at_end = nil unless (ial_at_end && ial_at_end.size > 0)
+MaRuKu::In::Markdown.register_block_extension(
+  :regexp  => OpenDiv,
+  :handler => lambda do |doc, src, context|
+    first = src.shift_line
+    ial_at_beginning = first[OpenDiv, 1]
+    ial_at_end = nil
+
+    lines = []
+    # if second line starts with "|"
+    if src.cur_line =~ StartPipe
+      # then we read until no more "|"
+      while src.cur_line && src.cur_line =~ StartPipe
+        lines.push $1
+        src.shift_line
+      end
+      if src.cur_line =~ DecorativeClosing
+        ial_at_end = $1
+        src.shift_line
+      end
+    else
+      # else we read until CloseDiv
+      divs_open = 1
+      while src.cur_line && divs_open > 0
+        if src.cur_line =~ CloseDiv
+          divs_open -= 1
+          if divs_open == 0
+            ial_at_end = $1
+            src.shift_line
+            break
+          else
+            lines.push src.shift_line
+          end
+        else
+          if src.cur_line =~ OpenDiv
+            divs_open += 1
+          end
+          lines.push src.shift_line
+        end
+      end
+
+      if divs_open > 0
+        doc.maruku_error("At end of input, I still have #{divs_open} DIVs open.",
+          src, context)
+        next true
+      end
+    end
+
+    ial_at_beginning = nil unless ial_at_beginning && ial_at_beginning.size > 0
+    ial_at_end = nil unless ial_at_end && ial_at_end.size > 0
+
+    if ial_at_beginning && ial_at_end
+      doc.maruku_error("Found two conflicting IALs: #{ial_at_beginning.inspect} and #{ial_at_end.inspect}",
+        src, context)
+    end
 
-		if ial_at_beginning && ial_at_end
-			e = "Found two conflicting IALs: #{ial_at_beginning.inspect} and #{ial_at_end.inspect}"
-			doc.maruku_error(e, src, context)
-		end
-		
-		al_string = ial_at_beginning || ial_at_end
-		al = nil
-		
-		if al_string =~ /^\{(.*)\}\s*$/
-			inside = $1
-		cs = MaRuKu::In::Markdown::SpanLevelParser::CharSource
-		al = al_string &&
-			doc.read_attribute_list(cs.new(inside), its_context=nil, break_on=[nil])
-		end
-		
-		src = MaRuKu::In::Markdown::BlockLevelParser::LineSource.new(lines)
-		children = doc.parse_blocks(src)
+    al_string = ial_at_beginning || ial_at_end
+    al = nil
 
-		context.push doc.md_div(children, al)
-		true
-	})
-	
+    if al_string =~ /^\{(.*)\}\s*$/
+      al = al_string && doc.read_attribute_list(
+        MaRuKu::In::Markdown::SpanLevelParser::CharSource.new($1),
+        nil, [nil])
+    end
 
-module MaRuKu; class MDElement
+    context.push(
+      doc.md_div(
+        doc.parse_blocks(
+          MaRuKu::In::Markdown::BlockLevelParser::LineSource.new(lines)),
+        al))
+    true
+  end)
 
-	def md_div(children, al=nil)
-		type = label = num = nil
-		doc.refid2ref ||= {}
-		if al
-			al.each do |k, v|
-				case k
-				when :class
-					type = $1 if v =~ /^num_(\w*)/
-        	                when :id
-					label = v
-				end
-			end
-		end
-		if type
-			doc.refid2ref[type] ||= {}
-			num = doc.refid2ref[type].length + 1 || 1
-		end
-		e = self.md_el(:div, children, meta={:label => label, :type => type, :num => num}, al)
-		if type && label
-			doc.refid2ref[type].update({label => e})
-		end
-		e
-	end
-	
-end end
+module MaRuKu
+  class MDElement
+    def md_div(children, al = nil)
+      type = label = num = nil
+      doc.refid2ref ||= {}
+      if al
+        al.each do |k, v|
+          case k
+          when :class; type = $1 if v =~ /^num_(\w*)/
+          when :id; label = v
+          end
+        end
+      end
 
+      if type
+        doc.refid2ref[type] ||= {}
+        num = doc.refid2ref[type].length + 1
+        if !label
+          doc.id_counter += 1
+      		label =  "div_" + doc.id_counter.to_s
+        end
+      end
 
-module MaRuKu; module Out; module HTML
+      e = self.md_el(:div, children, {:label => label, :type => type, :num => num}, al)
+      doc.refid2ref[type].update(label => e) if type && label
+      e
+    end
+  end
 
-	def to_html_div
-		add_ws  wrap_as_element('div')
-	end
-	
-end end end
+  module Out
+    module HTML
+      def to_html_div
+        add_ws wrap_as_element('div')
+      end
+    end
+  end
+end
diff --git a/lib/maruku/ext/fenced_code.rb b/lib/maruku/ext/fenced_code.rb
new file mode 100644
index 0000000..13240ea
--- /dev/null
+++ b/lib/maruku/ext/fenced_code.rb
@@ -0,0 +1,97 @@
+# fenced_code.rb -- Maruku extension for fenced code blocks
+#
+# Copyright (C) 2009 Jason R. Blevins
+# 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 names of the copyright holders nor the names of any
+#    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 HOLDER 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.
+
+
+# Fenced code blocks begin with three or more tildes and are terminated
+# by a closing line with at least as many tildes as the opening line.
+# Optionally, an attribute list may appear at the end of the opening
+# line.  For example:
+#
+# ~~~~~~~~~~~~~ {: lang=ruby }
+# puts 'Hello world'
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# Or:
+#
+# ```ruby
+# puts 'Hello world'
+# ```
+#
+
+#=begin maruku_doc
+# Attribute: :fenced_code_blocks
+# Scope: global, document
+# Summary: Enables fenced code blocks
+#=end
+
+module Maruku::In::Markdown
+  module FencedCode
+    OpenFence = /^([`~]{3,})(\w+)?\s*(\{([^{}]*?|".*?"|'.*?')*\})?\s*$/
+  end
+end
+
+MaRuKu::In::Markdown::register_block_extension(
+  :regexp  => Maruku::In::Markdown::FencedCode::OpenFence,
+  :handler => lambda do |doc, src, context|
+    return false unless doc.get_setting :fenced_code_blocks
+
+    first = src.shift_line
+    first =~ Maruku::In::Markdown::FencedCode::OpenFence
+    close_fence = /^#{$1}[`~]*$/
+    lang = $2
+    ial = $3
+
+    lines = []
+
+    # read until CloseFence
+    while src.cur_line
+      if src.cur_line =~ close_fence
+        src.shift_line
+        break
+      else
+        lines << src.shift_line
+      end
+    end
+
+    ial = nil unless ial && ial.size > 0
+    al = nil
+
+    if ial =~ /^\{(.*?)\}\s*$/
+      inside = $1
+      cs = MaRuKu::In::Markdown::SpanLevelParser::CharSource
+      al = ial && doc.read_attribute_list(cs.new(inside))
+    end
+
+    source = lines.join("\n")
+    context.push doc.md_codeblock(source, lang, al)
+    true
+  end
+)
diff --git a/lib/maruku/ext/math.rb b/lib/maruku/ext/math.rb
index 8f65371..e80bcf2 100644
--- a/lib/maruku/ext/math.rb
+++ b/lib/maruku/ext/math.rb
@@ -1,5 +1,3 @@
-
-
 require 'maruku/ext/math/elements'
 require 'maruku/ext/math/parsing'
 require 'maruku/ext/math/to_latex'
@@ -10,32 +8,30 @@ require 'maruku/ext/math/mathml_engines/ritex'
 require 'maruku/ext/math/mathml_engines/itex2mml'
 require 'maruku/ext/math/mathml_engines/blahtex'
 
-
-=begin maruku_doc
-Attribute: math_enabled
-Scope: global, document
-Summary: Enables parsing of LaTeX math 
-
-To explicitly disable the math parsing:
-
-	Maruku.new(string, {:math_enabled => false})
-	{:ruby}
-	
-=end
+#=begin maruku_doc
+# Attribute: math_enabled
+# Scope: global, document
+# Summary: Enables parsing of LaTeX math
+#
+# To explicitly disable the math parsing:
+#
+# 	Maruku.new(string, {:math_enabled => false})
+# 	{:ruby}
+#
+#=end
 
 MaRuKu::Globals[:math_enabled] = true
 
 
-=begin maruku_doc
-Attribute: math_numbered
-Scope: global, document
-Summary: Math openings which should be numerated
-
-Array containing any of `'\\['`, `'\\begin{equation}'`, `'$$'`.
-
-	MaRuKu::Globals[:math_numbered] = ['\\[']
-	
-=end
-
+#=begin maruku_doc
+# Attribute: math_numbered
+# Scope: global, document
+# Summary: Math openings which should be numerated
+#
+# Array containing any of `'\\['`, `'\\begin{equation}'`, `'$$'`.
+#
+# 	MaRuKu::Globals[:math_numbered] = ['\\[']
+#
+#=end
 
-MaRuKu::Globals[:math_numbered] = [] 
+MaRuKu::Globals[:math_numbered] = []
diff --git a/lib/maruku/ext/math/elements.rb b/lib/maruku/ext/math/elements.rb
index f0ba3c0..b49b9c8 100644
--- a/lib/maruku/ext/math/elements.rb
+++ b/lib/maruku/ext/math/elements.rb
@@ -1,27 +1,21 @@
-module MaRuKu; class MDElement
-	
-	def md_inline_math(math)
-		self.md_el(:inline_math, [], meta={:math=>math})
-	end
+module MaRuKu
+  class MDElement
+    def md_inline_math(math)
+      self.md_el(:inline_math, [], :math => math)
+    end
 
-	def md_equation(math, label, numerate)
-		reglabel= /\\label\{(\w+)\}/
-		if math =~ reglabel
-			label = $1
-			math.gsub!(reglabel,'')
-		end
-#		puts "Found label = #{label} math #{math.inspect} "
-		num = nil
-		if (label || numerate) && @doc #take number
-			@doc.eqid2eq ||= {}	
-			num = @doc.eqid2eq.size + 1
-			label = "eq#{num}" if not label      # FIXME do id for document
-		end
-		e = self.md_el(:equation, [], meta={:math=>math, :label=>label,:num=>num})
-		if label && @doc #take number
-			@doc.eqid2eq[label] = e
-		end
-		e
-	end
-
-end end
\ No newline at end of file
+    def md_equation(math, label, numerate)
+      reglabel = /\\label\{(\w+)\}/
+      math = math.gsub(reglabel, '') if label = math[reglabel, 1]
+      num = nil
+      if (label || numerate) && @doc # take number
+        @doc.eqid2eq ||= {}
+        num = @doc.eqid2eq.size + 1
+        label = "eq#{num}" unless label # TODO do id for document
+      end
+      e = self.md_el(:equation, [], :math => math, :label => label, :num => num)
+      @doc.eqid2eq[label] = e if label && @doc # take number
+      e
+    end
+  end
+end
diff --git a/lib/maruku/ext/math/latex_fix.rb b/lib/maruku/ext/math/latex_fix.rb
deleted file mode 100644
index 35f1383..0000000
--- a/lib/maruku/ext/math/latex_fix.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class String
-	# fix some LaTeX command-name clashes
-	def fix_latex
-		if #{html_math_engine} == 'itex2mml'
-			s = self.gsub("\\mathop{", "\\operatorname{")
-			s.gsub!(/\\begin\{svg\}.*?\\end\{svg\}/m, " ")
-			s.gsub("\\space{", "\\itexspace{")
-		else
-			self
-		end
-	end
-end
diff --git a/lib/maruku/ext/math/mathml_engines/blahtex.rb b/lib/maruku/ext/math/mathml_engines/blahtex.rb
index b6cb30e..e1c24c0 100644
--- a/lib/maruku/ext/math/mathml_engines/blahtex.rb
+++ b/lib/maruku/ext/math/mathml_engines/blahtex.rb
@@ -1,107 +1,95 @@
-
-require 'tempfile'
 require 'fileutils'
 require 'digest/md5'
-require 'pstore'
-
-module MaRuKu; module Out; module HTML
-	
-	PNG = Struct.new(:src,:depth,:height)
-	
-	def convert_to_png_blahtex(kind, tex)
-		begin
-			FileUtils::mkdir_p get_setting(:html_png_dir)
-
-			# first, we check whether this image has already been processed
-			md5sum = Digest::MD5.hexdigest(tex+" params: ")
-			result_file = File.join(get_setting(:html_png_dir), md5sum+".txt")
-
-			if not File.exists?(result_file) 
-				tmp_in = Tempfile.new('maruku_blahtex')
-				f = tmp_in.open
-				f.write tex
-				f.close
-
-				resolution = get_setting(:html_png_resolution)
-
-				options = "--png --use-preview-package --shell-dvipng 'dvipng -D #{resolution}' "
-				options += "--displaymath " if kind == :equation
-				options += ("--temp-directory '%s' " % get_setting(:html_png_dir))
-				options += ("--png-directory '%s'" % get_setting(:html_png_dir))
-
-				cmd = "blahtex #{options} < #{tmp_in.path} > #{result_file}"
-				#$stderr.puts "$ #{cmd}"
-        system cmd
-				tmp_in.delete
-			end
-			
+require 'rexml/document'
+
+module MaRuKu::Out::HTML
+  PNG = Struct.new(:src, :depth, :height)
+
+  def convert_to_png_blahtex(kind, tex)
+    FileUtils.mkdir_p get_setting(:html_png_dir)
+
+    # first, we check whether this image has already been processed
+    md5sum = Digest::MD5.hexdigest(tex + " params: ")
+    result_file = File.join(get_setting(:html_png_dir), md5sum + ".txt")
+
+    if File.exists?(result_file)
       result = File.read(result_file)
-      if result.nil? || result.empty?
-        raise "Blahtex error: empty output"
-      end
-      
-			doc = Document.new(result, {:respect_whitespace =>:all})
-			png = doc.root.elements[1]
-			if png.name != 'png'
-				raise "Blahtex error: \n#{doc}"
-			end
-			depth = png.elements['depth'] || (raise "No depth element in:\n #{doc}")
-			height = png.elements['height'] || (raise "No height element in:\n #{doc}")
-			md5 = png.elements['md5'] || (raise "No md5 element in:\n #{doc}")
-			
-			depth = depth.text.to_f
-			height = height.text.to_f # XXX check != 0
-			md5 = md5.text
-			
-			dir_url = get_setting(:html_png_url)
-			return PNG.new("#{dir_url}#{md5}.png", depth, height)
-		rescue Exception => e
-			maruku_error "Error: #{e}"
-		end
-		nil
-	end
-
-  
-	def convert_to_mathml_blahtex(kind, tex)
-    @@BlahtexCache = PStore.new(get_setting(:latex_cache_file))
-    
-		begin
-			@@BlahtexCache.transaction do 
-				if @@BlahtexCache[tex].nil?
-					tmp_in = Tempfile.new('maruku_blahtex')
-						f = tmp_in.open
-						f.write tex
-						f.close
-					tmp_out = Tempfile.new('maruku_blahtex')
-	
-					options = "--mathml"
-					cmd = "blahtex #{options} < #{tmp_in.path} > #{tmp_out.path}"
-					#$stderr.puts "$ #{cmd}"
-					system cmd
-					tmp_in.delete
-					
-					result = nil
-					File.open(tmp_out.path) do |f| result=f.read end
-						puts result
-					
-          @@BlahtexCache[tex] = result
-				end
-			
-				blahtex = @@BlahtexCache[tex]
-				doc = Document.new(blahtex, {:respect_whitespace =>:all})
-				mathml = doc.root.elements['mathml']
-				if not mathml
-					maruku_error "Blahtex error: \n#{doc}"
-					return nil
-				else
-					return mathml
-				end
-			end
-			
-		rescue Exception => e
-			maruku_error "Error: #{e}"
-		end
-		nil
-	end
-
-end end end
+    else
+      args = [
+              '--png',
+              '--use-preview-package',
+              '--shell-dvipng',
+              "dvipng -D #{Shellwords.shellescape(get_setting(:html_png_resolution).to_s)}",
+              "--temp-directory #{Shellwords.shellescape(get_setting(:html_png_dir))}",
+              "--png-directory #{Shellwords.shellescape(get_setting(:html_png_dir))}"
+             ]
+      args << '--displaymath' if kind == :equation
+
+      result = run_blahtex(tex, args)
+    end
+
+    if result.nil? || result.empty?
+      maruku_error "Blahtex error: empty output"
+      return
+    end
+
+    doc = REXML::Document.new(result)
+    png = doc.root.elements.to_a.first
+    if png.name != 'png'
+      maruku_error "Blahtex error: \n#{doc}"
+      return
+    end
+
+    raise "No depth element in:\n #{doc}" unless depth = png.xpath('//depth')[0]
+    raise "No height element in:\n #{doc}" unless height = png.xpath('//height')[0]
+    raise "No md5 element in:\n #{doc}" unless md5 = png.xpath('//md5')[0]
+
+    depth = depth.text.to_f
+    height = height.text.to_f
+    raise "Height or depth was 0! in \n #{doc}" if height == 0 || depth == 0
+
+    md5 = md5.text
+
+    PNG.new("#{get_setting(:html_png_url)}#{md5}.png", depth, height)
+  rescue => e
+    maruku_error "Error: #{e}"
+    nil
+  end
+
+  def convert_to_mathml_blahtex(kind, tex)
+    result = run_blahtex(tex, %w[--mathml])
+
+    doc = REXML::Document.new(result)
+    mathml = doc.get_elements('//markup').to_a.first
+    unless mathml
+      maruku_error "Blahtex error: \n#{doc}"
+      return nil
+    end
+
+    mathml.name = 'math'
+    mathml.attributes['xmlns'] = "http://www.w3.org/1998/Math/MathML"
+    mathml.attributes['display'] = (kind == :inline) ? :inline : :block
+
+    MaRuKu::HTMLFragment.new(mathml.to_s)
+  rescue => e
+    maruku_error "Error: #{e}"
+    nil
+  end
+
+  private
+
+  # Run blahtex, return output
+  def run_blahtex(tex, args)
+    IO.popen(['blahtex', *args].join(' '), 'w+') do |blahtex|
+      blahtex.write tex
+      blahtex.close_write
+
+      output = blahtex.read
+      blahtex.close_read
+
+      raise "Error running blahtex" unless $?.success?
+
+      output
+    end
+  end
+end
diff --git a/lib/maruku/ext/math/mathml_engines/itex2mml.rb b/lib/maruku/ext/math/mathml_engines/itex2mml.rb
index 69d273d..f963520 100644
--- a/lib/maruku/ext/math/mathml_engines/itex2mml.rb
+++ b/lib/maruku/ext/math/mathml_engines/itex2mml.rb
@@ -1,29 +1,36 @@
+module MaRuKu::Out::HTML
+  def convert_to_mathml_itex2mml(kind, tex)
+    return if $already_warned_itex2mml
+    begin
+      require 'itextomml'
+    rescue LoadError => e
+      maruku_error "Could not load package 'itex2mml'.\nPlease install it." unless $already_warned_itex2mml
+      $already_warned_itex2mml = true
+      return nil
+    end
 
-module MaRuKu; module Out; module HTML
+    begin
+      require 'instiki_stringsupport'
+    rescue LoadError
+      require 'itex_stringsupport'
+    end
 
-	def convert_to_mathml_itex2mml(kind, tex)
-		begin
-			if not $itex2mml_parser
-				require 'itextomml'
-				$itex2mml_parser =  Itex2MML::Parser.new
-			end
-			
-			itex_method = {:equation=>:block_filter,:inline=>:inline_filter}
-			
-			mathml =  $itex2mml_parser.send(itex_method[kind], tex)
-			doc = Document.new(mathml, {:respect_whitespace =>:all}).root
-			return doc
-		rescue LoadError => e
-			maruku_error "Could not load package 'itex2mml'.\n"+ "Please install it." 			unless $already_warned_itex2mml 
-			$already_warned_itex2mml = true
-		rescue REXML::ParseException => e
-			maruku_error "Invalid MathML TeX: \n#{add_tabs(tex,1,'tex>')}"+
-				"\n\n #{e.inspect}"
-		rescue 
-			maruku_error "Could not produce MathML TeX: \n#{tex}"+
-				"\n\n #{e.inspect}"
-		end
-		nil
-	end
+    parser = Itex2MML::Parser.new
+    mathml =
+      case kind
+      when :equation
+        parser.block_filter(tex)
+      when :inline
+        parser.inline_filter(tex)
+      else
+        maruku_error "Unknown itex2mml kind: #{kind}"
+        return
+      end
+
+    MaRuKu::HTMLFragment.new(mathml.to_utf8)
+  rescue => e
+    maruku_error "Invalid MathML TeX: \n#{tex.gsub(/^/, 'tex>')}\n\n #{e.inspect}"
+    nil
+  end
+end
 
-end end end
diff --git a/lib/maruku/ext/math/mathml_engines/none.rb b/lib/maruku/ext/math/mathml_engines/none.rb
index 42f1df4..7c6b994 100644
--- a/lib/maruku/ext/math/mathml_engines/none.rb
+++ b/lib/maruku/ext/math/mathml_engines/none.rb
@@ -1,20 +1,12 @@
-module MaRuKu; module Out; module HTML
-
-	def convert_to_mathml_none(kind, tex)
-		# You can: either return a REXML::Element
-		#    return Element.new 'div'    
-		# or return an empty array on error
-		#    return []  
-		# or have a string parsed by REXML:
-		tex = tex.gsub('&','&')
-		mathml = "<code>#{tex}</code>"
-		return Document.new(mathml).root
-	end
-
-	def convert_to_png_none(kind, tex)
-		return nil
-	end
-
-
-end end end
+module MaRuKu::Out::HTML
+  def convert_to_mathml_none(kind, tex)
+    code = xelem('code')
+    tex_node = xtext(tex)
+    code << tex_node
+  end
+
+  def convert_to_png_none(kind, tex)
+    nil
+  end
+end
 
diff --git a/lib/maruku/ext/math/mathml_engines/ritex.rb b/lib/maruku/ext/math/mathml_engines/ritex.rb
index 199eff5..7bb1fb0 100644
--- a/lib/maruku/ext/math/mathml_engines/ritex.rb
+++ b/lib/maruku/ext/math/mathml_engines/ritex.rb
@@ -1,5 +1,4 @@
-module MaRuKu; module Out; module HTML
-
+module MaRuKu::Out::HTML
 	def convert_to_mathml_ritex(kind, tex)
 		begin
 			if not $ritex_parser
@@ -20,5 +19,4 @@ module MaRuKu; module Out; module HTML
 		end
 		nil
 	end
-	
-end end end
+end
diff --git a/lib/maruku/ext/math/parsing.rb b/lib/maruku/ext/math/parsing.rb
index ec32ea3..e99bf75 100644
--- a/lib/maruku/ext/math/parsing.rb
+++ b/lib/maruku/ext/math/parsing.rb
@@ -1,119 +1,113 @@
 module MaRuKu
-	
-	class MDDocument
-		# Hash equation id (String) to equation element (MDElement)
-		safe_attr_accessor :eqid2eq, Hash
-		
-		def is_math_enabled? 
-			get_setting :math_enabled
-		end
-	end
+  class MDDocument
+    # A hash of equation ids to equation elements
+    #
+    # @return [String => MDElement]
+    attr_accessor :eqid2eq
+
+    def is_math_enabled?
+      get_setting :math_enabled
+    end
+  end
 end
 
+# TODO: Properly scope all these regexps
+# Everything goes; takes care of escaping the "\$" inside the expression
+RegInlineMath = /\${1}((?:[^\$]|\\\$)+)\$/
+
+MaRuKu::In::Markdown.register_span_extension(
+  :chars => '$',
+  :regexp => RegInlineMath,
+  :handler => lambda do |doc, src, con|
+    next false unless doc.is_math_enabled?
+    next false unless m = src.read_regexp(RegInlineMath)
+    math = m.captures.compact.first
+    con.push doc.md_inline_math(math)
+    true
+  end)
+
+
+MathOpen1 = Regexp.escape('\\begin{equation}')
+MathClose1 = Regexp.escape('\\end{equation}')
+MathOpen2 = Regexp.escape('\\[')
+MathClose2 = Regexp.escape('\\]')
+MathOpen3 = Regexp.escape('$$')
+MathClose3 = Regexp.escape('$$')
+
+EqLabel = /(?:\((\w+)\))/
+EquationOpen = /#{MathOpen1}|#{MathOpen2}|#{MathOpen3}/
+EquationClose = /#{MathClose1}|#{MathClose2}|#{MathClose3}/
+
+# $1 is opening, $2 is tex
+EquationStart = /^[ ]{0,3}(#{EquationOpen})(.*)$/
+# $1 is tex, $2 is closing, $3 is tex
+EquationEnd = /^(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
+# $1 is opening, $2 is tex, $3 is closing, $4 is label
+OneLineEquation = /^[ ]{0,3}(#{EquationOpen})(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
+
+MaRuKu::In::Markdown.register_block_extension(
+  :regexp  => EquationStart,
+  :handler => lambda do |doc, src, con|
+    next false unless doc.is_math_enabled?
+    first = src.shift_line
+    if first =~ OneLineEquation
+      opening, tex, closing, label = $1, $2, $3, $4
+      numerate = doc.get_setting(:math_numbered).include?(opening)
+      con.push doc.md_equation(tex, label, numerate)
+      next true
+    end
+
+    opening, tex = first.scan(EquationStart).first
+    # ensure newline at end of first line of equation isn't swallowed
+    tex << "\n"
+    numerate = doc.get_setting(:math_numbered).include?(opening)
+    label = nil
+    loop do
+      unless src.cur_line
+        doc.maruku_error(
+          "Stream finished while reading equation\n\n" + tex.gsub(/^/, '$> '),
+          src, con)
+        break
+      end
+
+      line = src.shift_line
+      if line =~ EquationEnd
+        tex_line, closing = $1, $2
+        label = $3 if $3
+        tex << tex_line << "\n"
+        break
+      end
+
+      tex << line << "\n"
+    end
+    con.push doc.md_equation(tex, label, numerate)
+    true
+  end)
+
 
-	# Everything goes; takes care of escaping the "\$" inside the expression
-	RegInlineMath = /\${1}((?:[^\$]|\\\$)+)\$/
-	
-	MaRuKu::In::Markdown::register_span_extension(
-		:chars => ?$, 
-		:regexp => RegInlineMath, 
-		:handler => lambda { |doc, src, con|
-			return false if not doc.is_math_enabled?
-		
-			if m = src.read_regexp(RegInlineMath)
-				math = m.captures.compact.first
-				con.push doc.md_inline_math(math)
-				true
-			else
-				#puts "not math: #{src.cur_chars 10}"
-				false
-			end
-		}
-	)
-	
-	
-	MathOpen1 = Regexp.escape('\\begin{equation}')
-	MathClose1 = Regexp.escape('\\end{equation}')
-	MathOpen2 = Regexp.escape('\\[')
-	MathClose2 = Regexp.escape('\\]')
-	MathOpen3 = Regexp.escape('$$')
-	MathClose3 = Regexp.escape('$$')
-	
-	EqLabel = /(?:\((\w+)\))/
-	EquationOpen = /#{MathOpen1}|#{MathOpen2}|#{MathOpen3}/
-	EquationClose = /#{MathClose1}|#{MathClose2}|#{MathClose3}/
-	
-	# $1 is opening, $2 is tex
-	EquationStart = /^[ ]{0,3}(#{EquationOpen})(.*)$/
-	# $1 is tex, $2 is closing, $3 is tex
-	EquationEnd = /^(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
-	# $1 is opening, $2 is tex, $3 is closing, $4 is label
-	OneLineEquation = /^[ ]{0,3}(#{EquationOpen})(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
+# This adds support for \eqref
+RegEqrefLatex = /\\eqref\{(\w+?)\}/
+RegEqPar = /\(eq:(\w+?)\)/
+RegEqref = Regexp.union(RegEqrefLatex, RegEqPar)
 
-	MaRuKu::In::Markdown::register_block_extension(
-		:regexp  => EquationStart,
-		:handler => lambda { |doc, src, con|
-			return false if not doc.is_math_enabled?
-			first = src.shift_line
-			if first =~ OneLineEquation
-				opening, tex, closing, label = $1, $2, $3, $4
-				numerate = doc.get_setting(:math_numbered).include?(opening)
-				con.push doc.md_equation(tex, label, numerate)
-			else
-				first =~ EquationStart
-				opening, tex = $1, $2
-				
-				numerate = doc.get_setting(:math_numbered).include?(opening)
-				label = nil
-				while true
-					if not src.cur_line
-						doc.maruku_error("Stream finished while reading equation\n\n"+
-							doc.add_tabs(tex,1,'$> '), src, con)
-						break
-					end
-					line = src.shift_line
-					if line =~ EquationEnd
-						tex_line, closing = $1, $2
-						label = $3 if $3
-						tex += tex_line + "\n"
-						break
-					else
-						tex += line + "\n"
-					end
-				end
-				con.push doc.md_equation(tex, label, numerate)
-			end
-			true
-		})
-		
-		
-	# This adds support for \eqref
-	RegEqrefLatex = /\\eqref\{(\w+)\}/
-	RegEqPar = /\(eq:(\w+)\)/
-	RegEqref = Regexp::union(RegEqrefLatex, RegEqPar)
-	
-	MaRuKu::In::Markdown::register_span_extension(
-		:chars => [?\\, ?(], 
-		:regexp => RegEqref,
-		:handler => lambda { |doc, src, con|
-			return false if not doc.is_math_enabled?
-			eqid = src.read_regexp(RegEqref).captures.compact.first
-			r = doc.md_el(:eqref, [], meta={:eqid=>eqid})
-			con.push r
-	 		true 
-		}
-	)
+MaRuKu::In::Markdown.register_span_extension(
+  :chars => ["\\", '('],
+  :regexp => RegEqref,
+  :handler => lambda do |doc, src, con|
+    return false unless doc.is_math_enabled?
+    eqid = src.read_regexp(RegEqref).captures.compact.first
+    con.push doc.md_el(:eqref, [], :eqid => eqid)
+    true
+  end)
 
-	# This adds support for \ref
-	RegRef = /\\ref\{(\w*)\}/
-        MaRuKu::In::Markdown::register_span_extension(
-                :chars => [?\\, ?(], 
-                :regexp => RegRef,
-                :handler => lambda { |doc, src, con|
-                        return false if not doc.is_math_enabled?
-                        refid = src.read_regexp(RegRef).captures.compact.first
-                        r = doc.md_el(:divref, [], meta={:refid=>refid})
-                        con.push r
-                        true 
-                }
-        )
+# This adds support for \ref
+RegRef = /\\ref\{(\w*?)\}/
+MaRuKu::In::Markdown.register_span_extension(
+  :chars => ["\\", '('],
+  :regexp => RegRef,
+  :handler => lambda do |doc, src, con|
+    return false unless doc.is_math_enabled?
+    refid = src.read_regexp(RegRef).captures.compact.first
+    con.push doc.md_el(:divref, [], :refid => refid)
+    true
+  end)
diff --git a/lib/maruku/ext/math/to_html.rb b/lib/maruku/ext/math/to_html.rb
index eec3748..97f09a3 100644
--- a/lib/maruku/ext/math/to_html.rb
+++ b/lib/maruku/ext/math/to_html.rb
@@ -1,187 +1,177 @@
-
-=begin maruku_doc
-Extension: math
-Attribute: html_math_engine
-Scope: document, element
-Output: html
-Summary: Select the rendering engine for MathML.
-Default: <?mrk Globals[:html_math_engine].to_s ?>
-
-Select the rendering engine for math.
-
-If you want to use your custom engine `foo`, then set:
-
-	HTML math engine: foo
-{:lang=markdown}
-
-and then implement two functions:
-
-	def convert_to_mathml_foo(kind, tex)
-		...
-	end
-=end
-
-=begin maruku_doc
-Extension: math
-Attribute: html_png_engine
-Scope: document, element
-Output: html
-Summary: Select the rendering engine for math.
-Default: <?mrk Globals[:html_math_engine].to_s ?>
-
-Same thing as `html_math_engine`, only for PNG output.
-
-	def convert_to_png_foo(kind, tex)
-		# same thing
-		...
-	end
-{:lang=ruby}
-
-=end
-
-module MaRuKu; module Out; module HTML
-
-
-	
-	# Creates an xml Mathml document of self.math
-	def render_mathml(kind, tex)
-		engine = get_setting(:html_math_engine)
-		method = "convert_to_mathml_#{engine}".to_sym
-		if self.respond_to? method
-			mathml = self.send(method, kind, tex) 
-			return mathml || convert_to_mathml_none(kind, tex)
-		else 
-			puts "A method called #{method} should be defined."
-			return convert_to_mathml_none(kind, tex)
-		end
-	end
-
-	# Creates an xml Mathml document of self.math
-	def render_png(kind, tex)
-		engine = get_setting(:html_png_engine)
-		method = "convert_to_png_#{engine}".to_sym
-		if self.respond_to? method
-			return self.send(method, kind, tex) 
-		else 
-			puts "A method called #{method} should be defined."
-			return nil
-		end
-	end
-	
-	def pixels_per_ex
-		if not $pixels_per_ex 
-			x = render_png(:inline, "x")
-			$pixels_per_ex  = x.height # + x.depth
-		end
-		$pixels_per_ex
-	end
-		
-	def adjust_png(png, use_depth)
-		src = png.src
-		
-		height_in_px = png.height
-		depth_in_px = png.depth
-		height_in_ex = height_in_px / pixels_per_ex
-		depth_in_ex = depth_in_px / pixels_per_ex
-		total_height_in_ex = height_in_ex + depth_in_ex
-		style = "" 
-		style += "vertical-align: -#{depth_in_ex}ex;" if use_depth
-		style += "height: #{total_height_in_ex}ex;"
-		img = Element.new 'img'
-		img.attributes['src'] = src
-		img.attributes['style'] = style
-		img.attributes['alt'] = "$#{self.math.strip}$"
-		img
-	end
-	
-	def to_html_inline_math
-		mathml  = get_setting(:html_math_output_mathml) && render_mathml(:inline, self.math)
-		png = get_setting(:html_math_output_png) &&  render_png(:inline, self.math)
-
-		span = create_html_element 'span'
-		add_class_to(span, 'maruku-inline')
-			
-			if mathml
-				add_class_to(mathml, 'maruku-mathml')
-				return mathml
-			end
-	
-			if png
-				img = adjust_png(png, use_depth=true)
-				add_class_to(img, 'maruku-png')
-				span << img
-			end
-		span
-		
-	end
-
-	def to_html_equation
-		mathml  = get_setting(:html_math_output_mathml) && render_mathml(:equation, self.math)
-		png     = get_setting(:html_math_output_png)    && render_png(:equation, self.math)
-		
-		div = create_html_element 'div'
-		add_class_to(div, 'maruku-equation')
-			if mathml
-				add_class_to(mathml, 'maruku-mathml')
-				div << mathml 
-			end
-			
-			if png
-				img = adjust_png(png, use_depth=false)
-				add_class_to(img, 'maruku-png')
-				div << img
-			end
-			
-			source_span = Element.new 'span'
-			add_class_to(source_span, 'maruku-eq-tex')
-			code = convert_to_mathml_none(:equation, self.math.strip)	
-			code.attributes['style'] = 'display: none'
-			source_span << code
-			div << source_span
-
-			if self.label  # then numerate
-				span = Element.new 'span'
-				span.attributes['class'] = 'maruku-eq-number'
-				num = self.num
-				span << Text.new("(#{num})")
-				div << span
-				div.attributes['id'] = "eq:#{self.label}"
-			end
-		div
-	end
-	
-	def to_html_eqref
-		if eq = self.doc.eqid2eq[self.eqid]
-			num = eq.num
-			a = Element.new 'a'
-			a.attributes['class'] = 'maruku-eqref'
-			a.attributes['href'] = "#eq:#{self.eqid}"
-			a << Text.new("(#{num})")
-			a
-		else
-			maruku_error "Cannot find equation #{self.eqid.inspect}"
-			Text.new "(eq:#{self.eqid})"
-		end
-	end
-
-	def to_html_divref
-		ref= nil
-		self.doc.refid2ref.each_value { |h|
-			ref = h[self.refid] if h.has_key?(self.refid)			
-		}
-		if ref
-			num = ref.num
-                        a = Element.new 'a'
-                        a.attributes['class'] = 'maruku-ref'
-                        a.attributes['href'] = "#" + self.refid
-                        a << Text.new(num.to_s)
-                        a
-                else
-                        maruku_error "Cannot find div #{self.refid.inspect}"
-                        Text.new "\\ref{#{self.refid}}"
-                end
-	end
-	
-end end end
-
-
+#=begin maruku_doc
+# Extension: math
+# Attribute: html_math_engine
+# Scope: document, element
+# Output: html
+# Summary: Select the rendering engine for MathML.
+# Default: <?mrk Globals[:html_math_engine].to_s ?>
+#
+# Select the rendering engine for math.
+#
+# If you want to use your custom engine `foo`, then set:
+#
+#   HTML math engine: foo
+# {:lang=markdown}
+#
+# and then implement two functions:
+#
+#   def convert_to_mathml_foo(kind, tex)
+#     ...
+#   end
+#=end
+
+#=begin maruku_doc
+# Extension: math
+# Attribute: html_png_engine
+# Scope: document, element
+# Output: html
+# Summary: Select the rendering engine for math.
+# Default: <?mrk Globals[:html_math_engine].to_s ?>
+#
+# Same thing as `html_math_engine`, only for PNG output.
+#
+#   def convert_to_png_foo(kind, tex)
+#     # same thing
+#     ...
+#   end
+# {:lang=ruby}
+#
+#=end
+
+module MaRuKu
+  module Out
+    module HTML
+      # Creates an xml Mathml document of this node's TeX code.
+      #
+      # @return [MaRuKu::Out::HTML::HTMLElement]
+      def render_mathml(kind, tex)
+        engine = get_setting(:html_math_engine)
+        method = "convert_to_mathml_#{engine}"
+        if self.respond_to? method
+          mathml = self.send(method, kind, tex)
+          return mathml || convert_to_mathml_none(kind, tex)
+        end
+
+        # TODO: Warn here
+        raise "A method called #{method} should be defined."
+        convert_to_mathml_none(kind, tex)
+      end
+
+      # Renders a PNG image of this node's TeX code.
+      # Returns
+      #
+      # @return [MaRuKu::Out::HTML::PNG, nil]
+      #   A struct describing the location and size of the image,
+      #   or nil if no library is loaded that can render PNGs.
+      def render_png(kind, tex)
+        engine = get_setting(:html_png_engine)
+        method = "convert_to_png_#{engine}".to_sym
+        return self.send(method, kind, tex) if self.respond_to? method
+
+        raise "A method called #{method} should be defined."
+        nil
+      end
+
+      def pixels_per_ex
+        $pixels_per_ex ||= render_png(:inline, "x").height
+      end
+
+      def adjust_png(png, use_depth)
+        src = png.src
+
+        height_in_px = png.height
+        depth_in_px = png.depth
+        height_in_ex = height_in_px / pixels_per_ex
+        depth_in_ex = depth_in_px / pixels_per_ex
+        total_height_in_ex = height_in_ex + depth_in_ex
+        style = ""
+        style << "vertical-align: -#{depth_in_ex}ex;" if use_depth
+        style << "height: #{total_height_in_ex}ex;"
+
+        img = xelem('img')
+        img['src'] = src
+        img['style'] = style
+        img['alt'] = "$#{self.math.strip}$"
+        img['class'] = 'maruku-png'
+        img
+      end
+
+      def to_html_inline_math
+        mathml = get_setting(:html_math_output_mathml) && render_mathml(:inline, self.math)
+        if mathml
+          mathml.add_class('maruku-mathml')
+          return mathml.to_html
+        end
+
+        png = get_setting(:html_math_output_png) && render_png(:inline, self.math)
+
+        HTMLElement.new 'span', 'class' => 'maruku-inline' do
+          # TODO: It seems weird that we output an empty span if there's no PNG
+          if png
+            adjust_png(png, true)
+          end
+        end
+      end
+
+      def to_html_equation
+        mathml = get_setting(:html_math_output_mathml) && render_mathml(:equation, self.math)
+        png    = get_setting(:html_math_output_png)    && render_png(:equation, self.math)
+
+        div = xelem('div')
+        div['class'] = 'maruku-equation'
+        if mathml
+          if self.label  # then numerate
+            span = xelem('span')
+            span['class'] = 'maruku-eq-number'
+            span << xtext("(#{self.num})")
+            div << span
+            div['id'] = "eq:#{self.label}"
+          end
+          mathml.add_class('maruku-mathml')
+          div << mathml.to_html
+        end
+
+        if png
+          img = adjust_png(png, false)
+          div << img
+          if self.label  # then numerate
+            span = xelem('span')
+            span['class'] = 'maruku-eq-number'
+            span << xtext("(#{self.num})")
+            div << span
+            div['id'] = "eq:#{self.label}"
+          end
+        end
+
+        div
+      end
+
+      def to_html_eqref
+        unless eq = self.doc.eqid2eq[self.eqid]
+          maruku_error "Cannot find equation #{self.eqid.inspect}"
+          return xtext("(eq:#{self.eqid})")
+        end
+
+        a = xelem('a')
+        a['class'] = 'maruku-eqref'
+        a['href'] = "#eq:#{self.eqid}"
+        a << xtext("(#{eq.num})")
+        a
+      end
+
+      def to_html_divref
+        unless hash = self.doc.refid2ref.values.find {|h| h.has_key?(self.refid)}
+          maruku_error "Cannot find div #{self.refid.inspect}"
+          return xtext("\\ref{#{self.refid}}")
+        end
+        ref= hash[self.refid]
+
+        a = xelem('a')
+        a['class'] = 'maruku-ref'
+        a['href'] = "#" + self.refid
+        a << xtext(ref.num.to_s)
+        a
+      end
+    end
+  end
+end
diff --git a/lib/maruku/ext/math/to_latex.rb b/lib/maruku/ext/math/to_latex.rb
index 44f3866..b46a63d 100644
--- a/lib/maruku/ext/math/to_latex.rb
+++ b/lib/maruku/ext/math/to_latex.rb
@@ -1,26 +1,35 @@
-require 'maruku/ext/math/latex_fix'
+module MaRuKu
+  module Out
+    module Latex
+      def to_latex_inline_math
+        fix_latex("$#{self.math.strip}$")
+      end
 
-module MaRuKu; module Out; module Latex
+      def to_latex_equation
+        if self.label
+          fix_latex("\\begin{equation}\n#{self.math.strip}\n\\label{#{self.label}}\\end{equation}\n")
+        else
+          fix_latex("\\begin{displaymath}\n#{self.math.strip}\n\\end{displaymath}\n")
+        end
+      end
 
-	def to_latex_inline_math
-		"$#{self.math.strip}$".fix_latex
-	end
+      def to_latex_eqref
+        "\\eqref{#{self.eqid}}"
+      end
 
-	def to_latex_equation
-		if self.label
-			l =  "\\label{#{self.label}}"
-			"\\begin{equation}\n#{self.math.strip}\n#{l}\\end{equation}\n".fix_latex
-		else
-			"\\begin{displaymath}\n#{self.math.strip}\n\\end{displaymath}\n".fix_latex
-		end
-	end
-	
-	def to_latex_eqref
-		"\\eqref{#{self.eqid}}"
-	end
+      def to_latex_divref
+        "\\ref{#{self.refid}}"
+      end
 
-	def to_latex_divref
-       "\\ref{#{self.refid}}"
-	end
+      private
 
-end end end
\ No newline at end of file
+      def fix_latex(str)
+        return str unless self.get_setting(:html_math_engine) == 'itex2mml'
+        s = str.gsub("\\mathop{", "\\operatorname{")
+        s.gsub!(/\\begin\{svg\}.*?\\end\{svg\}/m, " ")
+        s.gsub!("\\array{","\\itexarray{")
+        s.gsub("\\space{", "\\itexspace{")
+      end
+    end
+  end
+end
diff --git a/lib/maruku/helpers.rb b/lib/maruku/helpers.rb
index 5f90c7c..2dce766 100644
--- a/lib/maruku/helpers.rb
+++ b/lib/maruku/helpers.rb
@@ -1,260 +1,161 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-
-
-# A series of helper functions for creating elements: they hide the 
-# particular internal representation.
-#
-# Please, always use these instead of creating MDElement.
-#
+require 'maruku/html'
 
 module MaRuKu
-module Helpers
-
-	# if the first is a md_ial, it is used as such
-	def md_el(node_type, children=[], meta={}, al=nil)
-		if  (e=children.first).kind_of?(MDElement) and 
-			e.node_type == :ial then
-			if al
-				al += e.ial
-			else
-				al = e.ial
-			end
-			children.shift
-		end 
-		e = MDElement.new(node_type, children, meta, al)
-		e.doc = @doc
-		return e
-	end
-
-	def md_header(level, children, al=nil)
-		md_el(:header, children, {:level => level}, al)
-	end
-	
-	# Inline code
-	def md_code(code, al=nil)
-		md_el(:inline_code, [], {:raw_code => code}, al)
-	end
-
-	# Code block
-	def md_codeblock(source, al=nil)
-		md_el(:code, [], {:raw_code => source}, al)
-	end
-
-	def md_quote(children, al=nil)
-		md_el(:quote, children, {}, al)
-	end
-
-	def md_li(children, want_my_par, al=nil)
-		md_el(:li, children, {:want_my_paragraph=>want_my_par}, al)
-	end
-
-	def md_footnote(footnote_id, children, al=nil)
-		md_el(:footnote, children, {:footnote_id=>footnote_id}, al)
-	end
-
-	def md_abbr_def(abbr, text, al=nil)
-		md_el(:abbr_def, [], {:abbr=>abbr, :text=>text}, al)
-	end
-
-	def md_abbr(abbr, title)
-		md_el(:abbr, [abbr], {:title=>title})
-	end
-	
-	def md_html(raw_html, al=nil)
-		e = md_el(:raw_html, [], {:raw_html=>raw_html})
-		begin
-			# remove newlines and whitespace at begin
-			# end end of string, or else REXML gets confused
-			raw_html = raw_html.gsub(/\A\s*</,'<').
-			                    gsub(/>[\s\n]*\Z/,'>')
-			
-			raw_html = "<marukuwrap>#{raw_html}</marukuwrap>"
-			e.instance_variable_set :@parsed_html,
-			 	REXML::Document.new(raw_html)
-		rescue   	REXML::ParseException => ex
-			e.instance_variable_set :@parsed_html, nil
-			maruku_recover "REXML cannot parse this block of HTML/XML:\n"+
-			add_tabs(raw_html,1,'|') + "\n"+ex.inspect
-#			"  #{raw_html.inspect}\n\n"+ex.inspect
-		end
-		e
-	end
-		
-	def md_link(children, ref_id, al=nil)
-		md_el(:link, children, {:ref_id=>ref_id.downcase}, al)
-	end
-	
-	def md_im_link(children, url, title=nil, al=nil)
-		md_el(:im_link, children, {:url=>url,:title=>title}, al)
-	end
-	
-	def md_image(children, ref_id, al=nil)
-		md_el(:image, children, {:ref_id=>ref_id}, al)
-	end
-	
-	def md_im_image(children, url, title=nil, al=nil)
-		md_el(:im_image, children, {:url=>url,:title=>title},al)
-	end
-
-	def md_em(children, al=nil)
-		md_el(:emphasis, [children].flatten, {}, al)
-	end
-
-	def md_br()
-		md_el(:linebreak, [], {}, nil)
-	end
-
-	def md_hrule()
-		md_el(:hrule, [], {}, nil)
-	end
-
-	def md_strong(children, al=nil)
-		md_el(:strong, [children].flatten, {}, al)
-	end
-
-	def md_emstrong(children, al=nil)
-		md_strong(md_em(children), al)
-	end
-
-	# <http://www.example.com/>
-	def md_url(url, al=nil)
-		md_el(:immediate_link, [], {:url=>url}, al)
-	end
-	
-	# <andrea at rubyforge.org>
-	# <mailto:andrea at rubyforge.org>
-	def md_email(email, al=nil)
-		md_el(:email_address, [], {:email=>email}, al)
-	end
-	
-	def md_entity(entity_name, al=nil)
-		md_el(:entity, [], {:entity_name=>entity_name}, al)
-	end
-	
-	# Markdown extra
-	def md_foot_ref(ref_id, al=nil)
-		md_el(:footnote_reference, [], {:footnote_id=>ref_id}, al)
-	end
-	
-	def md_par(children, al=nil)
-		md_el(:paragraph, children, meta={}, al)
-	end
-
-	# [1]: http://url [properties]
-	def md_ref_def(ref_id, url, title=nil, meta={}, al=nil)
-		meta[:url] = url
-		meta[:ref_id] = ref_id
-		meta[:title] = title if title
-		md_el(:ref_definition, [], meta, al)
-	end
-	
-	# inline attribute list
-	def md_ial(al)
-		al = Maruku::AttributeList.new(al) if 
-			not al.kind_of?Maruku::AttributeList
-		md_el(:ial, [], {:ial=>al})
-	end
-
-	# Attribute list definition
-	def md_ald(id, al)
-		md_el(:ald, [], {:ald_id=>id,:ald=>al})
-	end
-	
-	# Server directive <?target code... ?>
-	def md_xml_instr(target, code)
-		md_el(:xml_instr, [], {:target=>target, :code=>code})
-	end
-
+  # A collection of helper functions for creating Markdown elements.
+  # They hide the particular internal representations.
+  #
+  # Always use these rather than creating an {MDElement} directly.
+  module Helpers
+    # @param children [MDElement, String, Array<MDElement, String>]
+    #   The child nodes.
+    #   If the first child is a \{#md\_ial}, it's merged with `al`
+    def md_el(node_type, children=[], meta={}, al=nil)
+      children = Array(children)
+
+      first = children.first
+      if first && first.is_a?(MDElement) && first.node_type == :ial
+        if al
+          al += first.ial
+        else
+          al = first.ial
+        end
+        children.shift
+      end
+
+      e = MDElement.new(node_type, children, meta, al)
+      e.doc = @doc
+      e
+    end
+
+    def md_header(level, children, al=nil)
+      md_el(:header, children, { :level => level }, al)
+    end
+
+    # Inline code
+    def md_code(code, al=nil)
+      md_el(:inline_code, [], { :raw_code => code }, al)
+    end
+
+    # Code block
+    def md_codeblock(source, lang=nil, al=nil)
+      md_el(:code, [], { :raw_code => source, :lang => lang }, al)
+    end
+
+    def md_quote(children, al=nil)
+      md_el(:quote, children, {}, al)
+    end
+
+    def md_li(children, want_my_par=false, al=nil)
+      md_el(:li, children, { :want_my_paragraph => want_my_par }, al)
+    end
+
+    def md_footnote(footnote_id, children, al=nil)
+      md_el(:footnote, children, { :footnote_id => footnote_id }, al)
+    end
+
+    def md_abbr_def(abbr, text, al=nil)
+      md_el(:abbr_def, [], { :abbr => abbr, :text => text }, al)
+    end
+
+    def md_abbr(abbr, title)
+      md_el(:abbr, abbr, :title => title)
+    end
+
+    def md_html(raw_html, al=nil)
+      e = MDHTMLElement.new(:raw_html, [], :raw_html => raw_html)
+      e.doc = @doc
+      begin
+        # Set this as an attribute so it doesn't get included
+        # in metadata comparisons
+        e.parsed_html = MaRuKu::HTMLFragment.new(raw_html)
+      rescue => ex
+        maruku_recover "Maruku cannot parse this block of HTML/XML:\n" +
+          raw_html.gsub(/^/, '|').rstrip + "\n" + ex.to_s
+      end
+      e
+    end
+
+    def md_link(children, ref_id, al=nil)
+      md_el(:link, children, { :ref_id => ref_id }, al)
+    end
+
+    def md_im_link(children, url, title = nil, al=nil)
+      md_el(:im_link, children, { :url => url, :title => title }, al)
+    end
+
+    def md_image(children, ref_id, al=nil)
+      md_el(:image, children, { :ref_id => ref_id }, al)
+    end
+
+    def md_im_image(children, url, title=nil, al=nil)
+      md_el(:im_image, children, { :url => url, :title => title }, al)
+    end
+
+    def md_em(children, al=nil)
+      md_el(:emphasis, children, {}, al)
+    end
+
+    def md_br
+      md_el(:linebreak, [], {}, nil)
+    end
+
+    def md_hrule
+      md_el(:hrule, [], {}, nil)
+    end
+
+    def md_strong(children, al=nil)
+      md_el(:strong, children, {}, al)
+    end
+
+    def md_emstrong(children, al=nil)
+      md_strong(md_em(children), al)
+    end
+
+    # A URL to be linkified (e.g. `<http://www.example.com/>`).
+    def md_url(url, al=nil)
+      md_el(:immediate_link, [], { :url => url }, al)
+    end
+
+    # An email to be linkified
+    # (e.g. `<andrea at rubyforge.org>` or `<mailto:andrea at rubyforge.org>`).
+    def md_email(email, al=nil)
+      md_el(:email_address, [], { :email => email }, al)
+    end
+
+    def md_entity(entity_name, al=nil)
+      md_el(:entity, [], { :entity_name => entity_name }, al)
+    end
+
+    # Markdown extra
+    def md_foot_ref(ref_id, al=nil)
+      md_el(:footnote_reference, [], { :footnote_id => ref_id }, al)
+    end
+
+    def md_par(children, al=nil)
+      md_el(:paragraph, children, {}, al)
+    end
+
+    # A definition of a reference (e.g. `[1]: http://url [properties]`).
+    def md_ref_def(ref_id, url, title=nil, meta={}, al=nil)
+      all_meta = meta.merge({ :url => url, :ref_id => ref_id })
+      all_meta[:title] ||= title
+      md_el(:ref_definition, [], all_meta, al)
+    end
+
+    # inline attribute list
+    def md_ial(al)
+      al = Maruku::AttributeList.new(al) unless al.is_a?(Maruku::AttributeList)
+      md_el(:ial, [], :ial => al)
+    end
+
+    # Attribute list definition
+    def md_ald(id, al)
+      md_el(:ald, [], :ald_id => id, :ald => al)
+    end
+
+    # A server directive (e.g. `<?target code... ?>`)
+    def md_xml_instr(target, code)
+      md_el(:xml_instr, [], :target => target, :code => code)
+    end
+  end
 end
-end
-
-module MaRuKu
-
-class MDElement	
-	# outputs abbreviated form  (this should be eval()uable to get the document)
-	def inspect2 
-		s = 
-		case @node_type
-		when :paragraph
-			"md_par(%s)" % children_inspect
-		when :footnote_reference
-			"md_foot_ref(%s)" % self.footnote_id.inspect
-		when :entity
-			"md_entity(%s)" % self.entity_name.inspect
-		when :email_address
-			"md_email(%s)" % self.email.inspect
-		when :inline_code
-			"md_code(%s)" % self.raw_code.inspect
-		when :raw_html
-			"md_html(%s)" % self.raw_html.inspect
-		when :emphasis 
-			"md_em(%s)" % children_inspect
-		when :strong
-			"md_strong(%s)" % children_inspect
-		when :immediate_link
-			"md_url(%s)" % self.url.inspect
-		when :image
-			"md_image(%s, %s)" % [
-				children_inspect, 
-				self.ref_id.inspect]
-		when :im_image
-			"md_im_image(%s, %s, %s)" % [
-				children_inspect, 
-				self.url.inspect,
-				self.title.inspect]
-		when :link
-				"md_link(%s,%s)" % [
-					children_inspect, self.ref_id.inspect]
-		when :im_link
-				"md_im_link(%s, %s, %s)" % [
-					children_inspect, 
-					self.url.inspect,
-					self.title.inspect,
-				]
-		when :ref_definition
-			"md_ref_def(%s, %s, %s)" % [
-					self.ref_id.inspect, 
-					self.url.inspect,
-					self.title.inspect
-				]
-		when :ial
-			"md_ial(%s)" % self.ial.inspect
-		else
-			return nil
-		end
-		if @al and not @al.empty? then 
-			s = s.chop + ", #{@al.inspect})"
-		end
-		s
-	end
-	
-end
-
-end
-
-
-
-
-
-
-
diff --git a/lib/maruku/html.rb b/lib/maruku/html.rb
new file mode 100644
index 0000000..e6715e7
--- /dev/null
+++ b/lib/maruku/html.rb
@@ -0,0 +1,251 @@
+require 'set'
+
+$warned_nokogiri = false
+
+module MaRuKu
+  HTML_INLINE_ELEMS = Set.new %w[a abbr acronym audio b bdi bdo big br button canvas caption cite code
+    col colgroup command datalist del details dfn dir em fieldset font form i img input ins
+    kbd label legend mark meter optgroup option progress q rp rt ruby s samp select small
+    source span strike strong sub summary sup tbody td tfoot th thead time tr track tt u var video wbr
+    animate animateColor animateMotion animateTransform circle clipPath defs desc ellipse
+    feGaussianBlur filter font-face font-face-name font-face-src foreignObject g glyph hkern
+    linearGradient line marker mask metadata missing-glyph mpath path pattern polygon polyline
+    radialGradient rect set stop svg switch text textPath title tspan use
+    annotation annotation-xml maction math menclose merror mfrac mfenced mi mmultiscripts mn mo
+    mover mpadded mphantom mprescripts mroot mrow mspace msqrt mstyle msub msubsup msup mtable
+    mtd mtext mtr munder munderover none semantics]
+
+  # Parse block-level markdown elements in these HTML tags
+  BLOCK_TAGS = Set.new %w[div section]
+
+  # This gets mixed into HTML MDElement nodes to hold the parsed document fragment
+  module HTMLElement
+    attr_accessor :parsed_html
+  end
+
+  # This is just a factory, not an actual class
+  module HTMLFragment
+
+    # HTMLFragment.new produces a concrete HTMLFragment implementation
+    # that is either a NokogiriHTMLFragment or a REXMLHTMLFragment.
+    def self.new(raw_html)
+      if !$warned_nokogiri && MaRuKu::Globals[:html_parser] == 'nokogiri'
+        begin
+          require 'nokogiri'
+          return NokogiriHTMLFragment.new(raw_html)
+        rescue LoadError
+          warn "Nokogiri could not be loaded. Falling back to REXML."
+          $warned_nokogiri = true
+        end
+      end
+
+      require 'rexml/document'
+      REXMLHTMLFragment.new(raw_html)
+    end
+  end
+
+  # Nokogiri backend for HTML handling
+  class NokogiriHTMLFragment
+    def initialize(raw_html)
+      # Wrap our HTML in a dummy document with a doctype (just
+      # for the entity references)
+      wrapped = '<!DOCTYPE html PUBLIC
+  "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
+  "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
+<html>' + raw_html.strip + '</html>'
+
+      d = Nokogiri::XML::Document.parse(wrapped) {|c| c.nonet }
+      @fragment = d.root
+    end
+
+    # @return The name of the first child element in the fragment.
+    def first_node_name
+      first_child = @fragment.children.first
+      first_child ? first_child.name : nil
+    end
+
+    # Add a class to the children of this fragment
+    def add_class(class_name)
+      @fragment.children.each do |c|
+        c['class'] = ((c['class']||'').split(' ') + [class_name]).join(' ')
+      end
+    end
+
+    # Process markdown within the contents of some elements and
+    # replace their contents with the processed version.
+    #
+    # @param doc [MaRuKu::MDDocument] A document to process.
+    def process_markdown_inside_elements(doc)
+      # find span elements or elements with 'markdown' attribute
+      elts = @fragment.css("[markdown]")
+
+      d = @fragment.children.first
+      if d && HTML_INLINE_ELEMS.include?(d.name)
+        elts << d unless d.attribute('markdown')
+        elts += span_descendents(d)
+      end
+
+      elts.each do |e|
+        how = e['markdown']
+        e.remove_attribute('markdown')
+
+        next if "0" == how # user requests no markdown parsing inside
+        parse_blocks = (how == 'block') || BLOCK_TAGS.include?(e.name)
+
+        # Select all text children of e
+        e.xpath("./text()").each do |original_text|
+          s = MaRuKu::Out::HTML.escapeHTML(original_text.text)
+          unless s.strip.empty?
+            parsed = parse_blocks ? doc.parse_text_as_markdown(s) : doc.parse_span(s)
+
+            # restore leading and trailing spaces
+            padding = /\A(\s*).*?(\s*)\z/.match(s)
+            parsed = [padding[1]] + parsed + [padding[2]] if padding
+
+            el = doc.md_el(:dummy, parsed)
+
+            # Nokogiri collapses consecutive Text nodes, so replace it by a dummy element
+            guard = Nokogiri::XML::Element.new('guard', @fragment)
+            original_text.replace(guard)
+            el.children_to_html.each do |x|
+              guard.before(x.to_s)
+            end
+            guard.remove
+          end
+        end
+      end
+    end
+
+    # Convert this fragment to an HTML or XHTML string.
+    # @return [String]
+    def to_html
+      output_options = Nokogiri::XML::Node::SaveOptions::DEFAULT_XHTML ^
+        Nokogiri::XML::Node::SaveOptions::FORMAT
+      @fragment.children.inject("") do |out, child|
+        out << child.serialize(:save_with => output_options, :encoding => 'UTF-8')
+      end
+    end
+
+    private
+
+    # Get all span-level descendents of the given element, recursively,
+    # as a flat NodeSet.
+    #
+    # @param e [Nokogiri::XML::Node] An element.
+    # @return [Nokogiri::XML::NodeSet]
+    def span_descendents(e)
+      ns = Nokogiri::XML::NodeSet.new(Nokogiri::XML::Document.new)
+      e.element_children.inject(ns) do |descendents, c|
+        if HTML_INLINE_ELEMS.include?(c.name)
+          descendents << c
+          descendents += span_descendents(c)
+        end
+        descendents
+      end
+    end
+  end
+
+  # An HTMLFragment implementation using REXML
+  class REXMLHTMLFragment
+    def initialize(raw_html)
+      wrapped = '<!DOCTYPE html PUBLIC
+  "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
+  "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
+<html>' + raw_html.strip + '</html>'
+
+      @fragment = REXML::Document.new(wrapped).root
+    end
+
+    # The name of the first element in the fragment
+    def first_node_name
+      first_child = @fragment.children.first
+      (first_child && first_child.respond_to?(:name)) ? first_child.name : nil
+    end
+
+    # Add a class to the children of this fragment
+    def add_class(class_name)
+      @fragment.each_element do |c|
+        c.attributes['class'] = ((c.attributes['class']||'').split(' ') + [class_name]).join(' ')
+      end
+    end
+
+    # Process markdown within the contents of some elements and
+    # replace their contents with the processed version.
+    def process_markdown_inside_elements(doc)
+      elts = []
+      @fragment.each_element('//*[@markdown]') do |e|
+        elts << e
+      end
+
+      d = @fragment.children.first
+      if d && HTML_INLINE_ELEMS.include?(first_node_name)
+        elts << d unless d.attributes['markdown']
+        elts += span_descendents(d)
+      end
+
+      # find span elements or elements with 'markdown' attribute
+      elts.each do |e|
+        # should we parse block-level or span-level?
+        how = e.attributes['markdown']
+        e.attributes.delete('markdown')
+
+        next if "0" == how # user requests no markdown parsing inside
+        parse_blocks = (how == 'block') || BLOCK_TAGS.include?(e.name)
+
+        # Select all text children of e
+        e.texts.each do |original_text|
+          s = MaRuKu::Out::HTML.escapeHTML(original_text.value)
+          unless s.strip.empty?
+            # TODO extract common functionality
+            parsed = parse_blocks ? doc.parse_text_as_markdown(s) : doc.parse_span(s)
+            # restore leading and trailing spaces
+            padding = /\A(\s*).*?(\s*)\z/.match(s)
+            parsed = [padding[1]] + parsed + [padding[2]] if padding
+
+            el = doc.md_el(:dummy, parsed)
+
+            new_html = "<dummy>"
+            el.children_to_html.each do |x|
+              new_html << x.to_s
+            end
+            new_html << "</dummy>"
+
+            newdoc = REXML::Document.new(new_html).root
+
+            p = original_text.parent
+            newdoc.children.each do |c|
+              p.insert_before(original_text, c)
+            end
+
+            p.delete(original_text)
+          end
+        end
+      end
+    end
+
+    def to_html
+      formatter = REXML::Formatters::Default.new(true)
+      @fragment.children.inject("") do |out, child|
+        out << formatter.write(child, '')
+      end
+    end
+
+    private
+
+    # Get all span-level descendents of the given element, recursively,
+    # as an Array.
+    #
+    # @param e [REXML::Element] An element.
+    # @return [Array]
+    def span_descendents(e)
+      descendents = []
+      e.each_element do |c|
+        name = c.respond_to?(:name) ? c.name : nil
+        if name && HTML_INLINE_ELEMS.include?(c.name)
+          descendents << c
+          descendents += span_descendents(c)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/maruku/input/charsource.rb b/lib/maruku/input/charsource.rb
index a3d1479..b07afa7 100644
--- a/lib/maruku/input/charsource.rb
+++ b/lib/maruku/input/charsource.rb
@@ -1,326 +1,279 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-module MaRuKu; module In; module Markdown; module SpanLevelParser
-
-# a string scanner coded by me
-class CharSourceManual; end
-
-# a wrapper around StringScanner
-class CharSourceStrscan; end
-
-# A debug scanner that checks the correctness of both
-# by comparing their output
-class CharSourceDebug; end
-
-# Choose!
-
-CharSource = CharSourceManual     # faster! 58ms vs. 65ms
-#CharSource = CharSourceStrscan
-#CharSource = CharSourceDebug
-
-
-class CharSourceManual
-	include MaRuKu::Strings
-	
-	def initialize(s, parent=nil)
-		raise "Passed #{s.class}" if not s.kind_of? String
-		@buffer = s
-		@buffer_index = 0
-		@parent = parent
-	end
-	
-	# Return current char as a FixNum (or nil).
-	def cur_char; @buffer[@buffer_index]   end
-
-	# Return the next n chars as a String.
-	def cur_chars(n); @buffer[@buffer_index,n]  end
-	
-	# Return the char after current char as a FixNum (or nil).
-	def next_char; @buffer[@buffer_index+1] end
-	
-	def shift_char
-		c = @buffer[@buffer_index]
-		@buffer_index+=1
-		c
-	end
-	
-	def ignore_char
-		@buffer_index+=1
-		nil
-	end
-	
-	def ignore_chars(n)
-		@buffer_index+=n
-		nil
-	end
-	
-	def current_remaining_buffer
-		@buffer[@buffer_index, @buffer.size- at buffer_index]
-	end
-	
-	def cur_chars_are(string)
-		# There is a bug here
-		if false
-			r2 = /^.{#{@buffer_index}}#{Regexp.escape string}/m
-			@buffer =~ r2
-		else
-			cur_chars(string.size) == string
-		end
-	end
-
-	def next_matches(r)
-		r2 = /^.{#{@buffer_index}}#{r}/m
-		md = r2.match @buffer
-		return !!md
-	end
-	
-	def read_regexp3(r)
-		r2 = /^.{#{@buffer_index}}#{r}/m
-		m = r2.match @buffer
-		if m
-			consumed = m.to_s.size - @buffer_index
-#			puts "Consumed #{consumed} chars (entire is #{m.to_s.inspect})"
-			ignore_chars consumed
-		else
-#			puts "Could not read regexp #{r2.inspect} from buffer "+
-#			" index=#{@buffer_index}"
-#			puts "Cur chars = #{cur_chars(20).inspect}"
-#			puts "Matches? = #{cur_chars(20) =~ r}"
-		end
-		m
-	end
-
-		def read_regexp(r)
-			r2 = /^#{r}/
-			rest = current_remaining_buffer
-			m = r2.match(rest)
-			if m
-				@buffer_index += m.to_s.size
-#				puts "#{r} matched #{rest.inspect}: #{m.to_s.inspect}"
-			end
-			return m
-		end
-	
-	def consume_whitespace
-		while c = cur_char 
-		  if (c == ?\s || c == ?\t)
-#				puts "ignoring #{c}"
-				ignore_char
-			else
-#				puts "#{c} is not ws: "<<c
-				break
-			end
-		end
-	end
-
-	def read_text_chars(out)
-		s = @buffer.size; c=nil
-		while @buffer_index < s && (c=@buffer[@buffer_index]) &&
-			 ((c>=?a && c<=?z) || (c>=?A && c<=?Z))
-				out << c
-				@buffer_index += 1
-		end
-	end
-	
-	def describe
-		s = describe_pos(@buffer, @buffer_index)
-		if @parent
-			s += "\n\n" + @parent.describe
-		end
-		s
-	end
-	include SpanLevelParser
-end
+require 'strscan'
 
-def describe_pos(buffer, buffer_index)
-	len = 75
-	num_before = [len/2, buffer_index].min
-	num_after = [len/2, buffer.size-buffer_index].min
-	num_before_max = buffer_index
-	num_after_max = buffer.size-buffer_index
-	
-#		puts "num #{num_before} #{num_after}"
-	num_before = [num_before_max, len-num_after].min
-	num_after  = [num_after_max, len-num_before].min
-#		puts "num #{num_before} #{num_after}"
-	
-	index_start = [buffer_index - num_before, 0].max
-	index_end   = [buffer_index + num_after, buffer.size].min
-	
-	size = index_end- index_start
-	
-#		puts "- #{index_start} #{size}"
-
-	str = buffer[index_start, size]
-	str.gsub!("\n",'N')
-	str.gsub!("\t",'T')
-	
-	if index_end == buffer.size 
-		str += "EOF"
-	end
-		
-	pre_s = buffer_index-index_start
-	pre_s = [pre_s, 0].max
-	pre_s2 = [len-pre_s,0].max
-#		puts "pre_S = #{pre_s}"
-	pre =" "*(pre_s) 
-	
-	"-"*len+"\n"+
-	str + "\n" +
-	"-"*pre_s + "|" + "-"*(pre_s2)+"\n"+
-#		pre + "|\n"+
-	pre + "+--- Byte #{buffer_index}\n"+
-	
-	"Shown bytes [#{index_start} to #{size}] of #{buffer.size}:\n"+
-	add_tabs(buffer,1,">")
-	
-#		"CharSource: At character #{@buffer_index} of block "+
-#		" beginning with:\n    #{@buffer[0,50].inspect} ...\n"+
-#		" before: \n     ... #{cur_chars(50).inspect} ... "
-end
+module MaRuKu::In::Markdown::SpanLevelParser
 
+  # a string scanner coded by me
+  class CharSourceManual; end
 
-require 'strscan'
+  # a wrapper around StringScanner
+  class CharSourceStrscan; end
 
-class CharSourceStrscan
-	include SpanLevelParser
-	include MaRuKu::Strings
-	
-	def initialize(s, parent=nil)
-		@s = StringScanner.new(s)
-		@parent = parent
-	end
-	
-	# Return current char as a FixNum (or nil).
-	def cur_char
-		 @s.peek(1)[0]
-	end
-
-	# Return the next n chars as a String.
-	def cur_chars(n); 
-		@s.peek(n)
-	end
-	
-	# Return the char after current char as a FixNum (or nil).
-	def next_char; 
-		@s.peek(2)[1]
-	end
-	
-	def shift_char
-		(@s.get_byte)[0]
-	end
-	
-	def ignore_char
-		@s.get_byte
-		nil
-	end
-	
-	def ignore_chars(n)
-		n.times do @s.get_byte end
-		nil
-	end
-	
-	def current_remaining_buffer
-		@s.rest #nil #@buffer[@buffer_index, @buffer.size- at buffer_index]
-	end
-	
-	def cur_chars_are(string)
-		cur_chars(string.size) == string
-	end
-
-	def next_matches(r)
-		len = @s.match?(r)
-		return !!len
-	end
-	
-	def read_regexp(r)
-		string = @s.scan(r)
-		if string
-			return r.match(string)
-		else
-			return nil
-		end
-	end
-	
-	def consume_whitespace
-		@s.scan(/\s+/)
-		nil
-	end
-	
-	def describe
-		describe_pos(@s.string, @s.pos)
-	end
-	
-end
+  # A debug scanner that checks the correctness of both
+  # by comparing their output
+  class CharSourceDebug; end
 
+  # Choose!
 
-class CharSourceDebug
-	def initialize(s, parent)
-		@a = CharSourceManual.new(s, parent)
-		@b = CharSourceStrscan.new(s, parent)
-	end
-	
-	def method_missing(methodname, *args)
-		a_bef = @a.describe
-		b_bef = @b.describe
-		
-		a = @a.send(methodname, *args)
-		b = @b.send(methodname, *args)
-		
-#		if methodname == :describe
-#			return a
-#		end
-		
-		if a.kind_of? MatchData
-			if a.to_a != b.to_a
-				puts "called: #{methodname}(#{args})"
-				puts "Matchdata:\na = #{a.to_a.inspect}\nb = #{b.to_a.inspect}"
-				puts "AFTER: "+ at a.describe
-				puts "AFTER: "+ at b.describe
-				puts "BEFORE: "+a_bef
-				puts "BEFORE: "+b_bef
-				puts caller.join("\n")
-				exit
-			end
-		else
-			if a!=b
-				puts "called: #{methodname}(#{args})"
-				puts "Attenzione!\na = #{a.inspect}\nb = #{b.inspect}"
-				puts ""+ at a.describe
-				puts ""+ at b.describe
-				puts caller.join("\n")
-				exit
-			end
-		end
-		
-		if @a.cur_char != @b.cur_char
-			puts "Fuori sincronia dopo #{methodname}(#{args})"
-			puts ""+ at a.describe
-			puts ""+ at b.describe
-			exit
-		end
-		
-		return a
-	end
-end
+  CharSource = CharSourceManual     # faster! 58ms vs. 65ms
+  #CharSource = CharSourceStrscan   # Faster on LONG documents. But StringScanner is buggy in Rubinius
+  #CharSource = CharSourceDebug
+
+
+  class CharSourceManual
+    def initialize(s, parent=nil)
+      raise "Passed #{s.class}" if not s.kind_of? String
+      @buffer = s
+      @buffer_index = 0
+      @parent = parent
+    end
+
+    # Return current char as a String (or nil).
+    def cur_char
+      cur_chars(1)
+    end
+
+    # Return the next n chars as a String.
+    def cur_chars(n)
+      return nil if @buffer_index >= @buffer.size
+      @buffer[@buffer_index, n]
+    end
+
+    # Return the char after current char as a String (or nil).
+    def next_char
+      return nil if @buffer_index + 1 >= @buffer.size
+      @buffer[@buffer_index + 1, 1]
+    end
+
+    def shift_char
+      c = cur_char
+      @buffer_index += 1
+      c
+    end
+
+    def ignore_char
+      @buffer_index += 1
+    end
+
+    def ignore_chars(n)
+      @buffer_index += n
+    end
+
+    def current_remaining_buffer
+      @buffer[@buffer_index, @buffer.size - @buffer_index]
+    end
+
+    def cur_chars_are(string)
+      cur_chars(string.size) == string
+    end
+
+    def next_matches(r)
+      r2 = /^.{#{@buffer_index}}#{r}/m
+      r2.match @buffer
+    end
+
+    def read_regexp(r)
+      r2 = /^#{r}/
+      rest = current_remaining_buffer
+      m = r2.match(rest)
+      if m
+        @buffer_index += m.to_s.size
+      end
+      m
+    end
+
+    def consume_whitespace
+      while c = cur_char
+        break unless (c == ' ' || c == "\t")
+        ignore_char
+      end
+    end
+
+    def describe
+      s = describe_pos(@buffer, @buffer_index)
+      if @parent
+        s += "\n\n" + @parent.describe
+      end
+      s
+    end
+
+    def describe_pos(buffer, buffer_index)
+      len = 75
+      num_before = [len/2, buffer_index].min
+      num_after = [len/2, buffer.size - buffer_index].min
+      num_before_max = buffer_index
+      num_after_max = buffer.size - buffer_index
+
+      num_before = [num_before_max, len - num_after].min
+      num_after  = [num_after_max, len - num_before].min
+
+      index_start = [buffer_index - num_before, 0].max
+      index_end   = [buffer_index + num_after, buffer.size].min
+
+      size = index_end - index_start
+
+      str = buffer[index_start, size]
+      str.gsub!("\n", 'N')
+      str.gsub!("\t", 'T')
+
+      if index_end == buffer.size
+        str += "EOF"
+      end
+
+      pre_s = buffer_index - index_start
+      pre_s = [pre_s, 0].max
+      pre_s2 = [len - pre_s, 0].max
+      pre = " " * pre_s
+
+      "-" * len + "\n" +
+        str + "\n" +
+        "-" * pre_s + "|" + "-" * pre_s2 + "\n" +
+        pre + "+--- Byte #{buffer_index}\n"+
 
-end end end end
+        "Shown bytes [#{index_start} to #{size}] of #{buffer.size}:\n"+
+        buffer.gsub(/^/, ">")
+    end
+  end
+
+  class CharSourceStrscan
+
+    def initialize(s, parent=nil)
+      @scanner = StringScanner.new(s)
+      @size = s.size
+    end
+
+    # Return current char as a String (or nil).
+    def cur_char
+      @scanner.peek(1)[0]
+    end
+
+    # Return the next n chars as a String.
+    def cur_chars(n)
+      @scanner.peek(n)
+    end
+
+    # Return the char after current char as a String (or nil).
+    def next_char
+      @scanner.peek(2)[1]
+    end
+
+    # Return a character as a String, advancing the pointer.
+    def shift_char
+      @scanner.getch[0]
+    end
+
+    # Advance the pointer
+    def ignore_char
+      @scanner.getch
+    end
+
+    # Advance the pointer by n
+    def ignore_chars(n)
+      n.times { @scanner.getch }
+    end
+
+    # Return the rest of the string
+    def current_remaining_buffer
+      @scanner.rest
+    end
+
+    # Returns true if string matches what we're pointing to
+    def cur_chars_are(string)
+      @scanner.peek(string.size) == string
+    end
+
+    # Returns true if Regexp r matches what we're pointing to
+    def next_matches(r)
+      @scanner.check(r)
+    end
+
+    def read_regexp(r)
+      r.match(@scanner.scan(r))
+    end
+
+    def consume_whitespace
+      @scanner.skip(/\s+/)
+    end
+
+    def describe
+      len = 75
+      num_before = [len/2, @scanner.pos].min
+      num_after = [len/2, @scanner.rest_size].min
+      num_before_max = @scanner.pos
+      num_after_max = @scanner.rest_size
+
+      num_before = [num_before_max, len - num_after].min
+      num_after  = [num_after_max, len - num_before].min
+
+      index_start = [@scanner.pos - num_before, 0].max
+      index_end   = [@scanner.pos + num_after, @size].min
+
+      size = index_end - index_start
+
+      str = @scanner.string[index_start, size]
+      str.gsub!("\n", 'N')
+      str.gsub!("\t", 'T')
+
+      if index_end == @size
+        str += "EOF"
+      end
+
+      pre_s = @scanner.pos - index_start
+      pre_s = [pre_s, 0].max
+      pre_s2 = [len-pre_s, 0].max
+      pre = " " * pre_s
+
+      "-" * len + "\n" +
+        str + "\n" +
+        "-" * pre_s + "|" + "-" * pre_s2 + "\n" +
+        pre + "+--- Byte #{@scanner.pos}\n" +
+        "Shown bytes [#{index_start} to #{size}] of #{@size}:\n" +
+        @scanner.string.gsub(/^/, ">")
+    end
+  end
+
+  class CharSourceDebug
+    def initialize(s, parent)
+      @a = CharSourceManual.new(s, parent)
+      @b = CharSourceStrscan.new(s, parent)
+    end
+
+    def method_missing(methodname, *args)
+      a_bef = @a.describe
+      b_bef = @b.describe
+
+      a = @a.send(methodname, *args)
+      b = @b.send(methodname, *args)
+
+      if a.kind_of? MatchData
+        if a.to_a != b.to_a
+          puts "called: #{methodname}(#{args})"
+          puts "Matchdata:\na = #{a.to_a.inspect}\nb = #{b.to_a.inspect}"
+          puts "AFTER: " + @a.describe
+          puts "AFTER: " + @b.describe
+          puts "BEFORE: " + a_bef
+          puts "BEFORE: " + b_bef
+          puts caller.join("\n")
+          exit
+        end
+      else
+        if a != b
+          puts "called: #{methodname}(#{args})"
+          puts "Attenzione!\na = #{a.inspect}\nb = #{b.inspect}"
+          puts "" + @a.describe
+          puts "" + @b.describe
+          puts caller.join("\n")
+          exit
+        end
+      end
+
+      if @a.cur_char != @b.cur_char
+        puts "Fuori sincronia dopo #{methodname}(#{args})"
+        puts "" + @a.describe
+        puts "" + @b.describe
+        exit
+      end
+
+      return a
+    end
+  end
+end
diff --git a/lib/maruku/input/extensions.rb b/lib/maruku/input/extensions.rb
index fc4cfb4..d7ef399 100644
--- a/lib/maruku/input/extensions.rb
+++ b/lib/maruku/input/extensions.rb
@@ -1,69 +1,68 @@
-module MaRuKu; module In; module Markdown
+module MaRuKu::In::Markdown
+  # Hash Fixnum -> name
+  SpanExtensionsTrigger = {}
 
 
-	# Hash Fixnum -> name
-	SpanExtensionsTrigger = {}
-	
-	
-	class SpanExtension
-		# trigging chars
-		attr_accessor :chars
-		# trigging regexp
-		attr_accessor :regexp
-		# lambda
-		attr_accessor :block
-	end
-	
-	# Hash String -> Extension
-	SpanExtensions = {}
+  class SpanExtension
+    # trigging chars
+    attr_accessor :chars
+    # trigging regexp
+    attr_accessor :regexp
+    # lambda
+    attr_accessor :block
+  end
 
-	def check_span_extensions(src, con)
-		c = src.cur_char
-		if extensions = SpanExtensionsTrigger[c]
-			extensions.each do |e|
-				if e.regexp && (match = src.next_matches(e.regexp))
-					return true if e.block.call(doc, src, con)
-				end
-			end
-		end
-		return false # not special
-	end
-	
-	def self.register_span_extension(args)
-		e = SpanExtension.new
-		e.chars = [*args[:chars]]
-		e.regexp = args[:regexp]
-		e.block = args[:handler] || raise("No blocks passed")
-		e.chars.each do |c|
-			(SpanExtensionsTrigger[c] ||= []).push e
-		end
-	end
+  # Hash String -> Extension
+  SpanExtensions = {}
 
-	def self.register_block_extension(args)
-		regexp = args[:regexp]
-		BlockExtensions[regexp] = (args[:handler] || raise("No blocks passed"))
-	end
+  def check_span_extensions(src, con)
+    c = src.cur_char
+    if extensions = SpanExtensionsTrigger[c]
+      extensions.each do |e|
+        if e.regexp && src.next_matches(e.regexp)
+          return true if e.block.call(doc, src, con)
+        end
+      end
+    end
 
-	# Hash Regexp -> Block
-	BlockExtensions = {}
+    false # not special
+  end
 
-	def check_block_extensions(src, con, line)
-		BlockExtensions.each do |reg, block|
-			if m = reg.match(line)
-				block = BlockExtensions[reg]
-				accepted =  block.call(doc, src, con)
-				return true if accepted
-			end
-		end
-		return false # not special
-	end
-	
-	def any_matching_block_extension?(line)
-		BlockExtensions.each_key do |reg|
-			m = reg.match(line)
-			return m if m
-		end
-		return false
-	end
-	
-end end end
+  def self.register_span_extension(args)
+    e = SpanExtension.new
+    e.chars = [*args[:chars]]
+    e.regexp = args[:regexp]
+    e.block = args[:handler] || raise("No blocks passed")
+    e.chars.each do |c|
+      (SpanExtensionsTrigger[c] ||= []).push e
+    end
+  end
+
+  def self.register_block_extension(args)
+    regexp = args[:regexp]
+    BlockExtensions[regexp] = (args[:handler] || raise("No blocks passed"))
+  end
+
+  # Hash Regexp -> Block
+  BlockExtensions = {}
+
+  def check_block_extensions(src, con, line)
+    BlockExtensions.each do |reg, block|
+      if reg.match(line)
+        block = BlockExtensions[reg]
+        accepted =  block.call(doc, src, con)
+        return true if accepted
+      end
+    end
+    false # not special
+  end
+
+  def any_matching_block_extension?(line)
+    BlockExtensions.each_key do |reg|
+      m = reg.match(line)
+      return m if m
+    end
+    false
+  end
+
+end
diff --git a/lib/maruku/input/html_helper.rb b/lib/maruku/input/html_helper.rb
index c2f5a8e..d3ba4e5 100644
--- a/lib/maruku/input/html_helper.rb
+++ b/lib/maruku/input/html_helper.rb
@@ -1,189 +1,233 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-module MaRuKu; module In; module Markdown; module SpanLevelParser
-
-# This class helps me read and sanitize HTML blocks
-
-# I tried to do this with REXML, but wasn't able to. (suggestions?)
-
-	class HTMLHelper
-		include MaRuKu::Strings
-		
-		Tag = %r{^<(/)?(\w+)\s*([^>]*)>}m
-		PartialTag = %r{^<.*}m
-
-		EverythingElse = %r{^[^<]+}m
-		CommentStart = %r{^<!--}x
-		CommentEnd = %r{^.*-->}
-		TO_SANITIZE = ['img','hr','br'] 
-		
-		attr_reader :rest
-		
-		def my_debug(s)
-#			puts "---"*10+"\n"+inspect+"\t>>>\t"s
-		end
-		
-		def initialize 
-			@rest = ""
-			@tag_stack = []
-			@m = nil
-			@already = ""
-			self.state = :inside_element
-		end
-
-		attr_accessor :state # = :inside_element, :inside_tag, :inside_comment,
-		
-		def eat_this(line)
-			@rest = line  + @rest
-			things_read = 0
-			until @rest.empty?
-				case self.state
-					when :inside_comment
-						if @m = CommentEnd.match(@rest)
-							@already += @m.pre_match + @m.to_s
-							@rest = @m.post_match
-							self.state = :inside_element
-						else 
-							@already += @rest 
-							@rest = ""
-							self.state = :inside_comment
-						end
-					when :inside_element 
-						if @m = CommentStart.match(@rest)
-							things_read += 1
-							@already += @m.pre_match + @m.to_s
-							@rest = @m.post_match
-							self.state = :inside_comment
-						elsif @m = Tag.match(@rest) then
-							my_debug "#{@state}: Tag: #{@m.to_s.inspect}"
-							things_read += 1
-							handle_tag
-							self.state = :inside_element
-						elsif @m = PartialTag.match(@rest) then
-							my_debug "#{@state}: PartialTag: #{@m.to_s.inspect}"
-							@already += @m.pre_match 
-							@rest = @m.post_match
-							@partial_tag = @m.to_s
-							self.state = :inside_tag
-						elsif @m = EverythingElse.match(@rest)
-							my_debug "#{@state}: Everything: #{@m.to_s.inspect}"
-							@already += @m.pre_match + @m.to_s
-							@rest = @m.post_match
-							self.state = :inside_element
-						else
-							error "Malformed HTML: not complete: #{@rest.inspect}"
-						end
-					when :inside_tag
-						if @m = /^[^>]*>/.match(@rest) then
-							my_debug "#{@state}: inside_tag: matched #{@m.to_s.inspect}"
-							@partial_tag += @m.to_s
-							my_debug "#{@state}: inside_tag: matched TOTAL: #{@partial_tag.to_s.inspect}"
-							@rest = @partial_tag + @m.post_match
-							@partial_tag = nil
-							self.state = :inside_element
-						else
-							@partial_tag += @rest
-							@rest = ""
-							self.state = :inside_tag
-						end
-					else
-						raise "Bug bug: state = #{self.state.inspect}"
-				end # not inside comment
-				
-#				puts inspect
-#				puts "Read: #{@tag_stack.inspect}"
-				break if is_finished? and things_read>0	
-			end
-		end
-
-		def handle_tag()
-			@already += @m.pre_match
-			@rest = @m.post_match
-
-			is_closing = !!@m[1]
-			tag = @m[2]
-			attributes = @m[3].to_s
-		
-			is_single = false
-			if attributes[-1] == ?/ # =~ /\A(.*)\/\Z/
-				attributes = attributes[0, attributes.size-1]
-				is_single = true
-			end
-
-			my_debug "Attributes: #{attributes.inspect}"
-			my_debug "READ TAG #{@m.to_s.inspect} tag = #{tag} closing? #{is_closing} single = #{is_single}"
-	
-			if TO_SANITIZE.include? tag 
-				attributes.strip!
-		#		puts "Attributes: #{attributes.inspect}"
-				if attributes.size > 0
-					@already +=  '<%s %s />' % [tag, attributes]
-				else
-					@already +=  '<%s />' % [tag]
-				end
-			elsif is_closing
-				@already += @m.to_s
-				if @tag_stack.empty?
-					error "Malformed: closing tag #{tag.inspect} "+
-					      "in empty list"
-				end 
-				if @tag_stack.last != tag
-					error "Malformed: tag <#{tag}> "+
-					      "closes <#{@tag_stack.last}>"
-				end
-				@tag_stack.pop
-			else 
-				@already += @m.to_s
-				
-				if not is_single
-					@tag_stack.push(tag) 
-					my_debug "Pushing #{tag.inspect} when read #{@m.to_s.inspect}"
-				end
-			end
-		end
-		def error(s)
-			raise Exception, "Error: #{s} \n"+ inspect, caller
-		end
-
-		def inspect; "HTML READER\n state=#{self.state} "+
-			"match=#{@m.to_s.inspect}\n"+
-			"Tag stack = #{@tag_stack.inspect} \n"+
-			"Before:\n"+
-			add_tabs(@already,1,'|')+"\n"+
-			"After:\n"+
-			add_tabs(@rest,1,'|')+"\n"
-			
-		end
-		
-		
-		def stuff_you_read
-			@already
-		end
-		
-		def rest() @rest end
-		
-		def is_finished?
-			(self.state == :inside_element)  and @tag_stack.empty?
-		end
-	end # html helper 
-
-end end end end
+module MaRuKu::In::Markdown::SpanLevelParser
+
+  # This class helps me read and sanitize HTML blocks
+  class HTMLHelper
+    Tag = %r{^<(/)?(\w+)\s*([^>]*?)>}m
+    PartialTag = %r{^<.*}m
+    CData = %r{^\s*<!\[CDATA\[}m
+    CDataEnd = %r{\]\]>}m
+
+    EverythingElse = %r{^[^<]+}m
+    CommentStart = %r{^<!--}x
+    CommentEnd = %r{-->}
+    TO_SANITIZE = ['img', 'hr', 'br']
+
+    attr_reader :rest, :first_tag
+
+    def initialize
+      @rest = ""
+      @tag_stack = []
+      @m = nil
+      @already = ""
+      self.state = :inside_element
+    end
+
+    attr_accessor :state # = :inside_element, :inside_tag, :inside_comment, :inside_cdata
+
+    def eat_this(line)
+      @rest = line + @rest
+      things_read = 0
+      until @rest.empty?
+        case self.state
+        when :inside_comment
+          if @m = CommentEnd.match(@rest)
+            debug_state 'Comment End'
+            # Workaround for https://bugs.ruby-lang.org/issues/9277 and another bug in 1.9.2 where even a
+            # single dash in a comment will cause REXML to error.
+            @already << @m.pre_match.gsub(/-(?![^\-])/, '- ') << @m.to_s
+            @rest = @m.post_match
+            self.state = :inside_element
+          else
+            @already << @rest.gsub(/-(?![^\-])/, '- ') # Workaround for https://bugs.ruby-lang.org/issues/9277
+            @rest = ""
+            self.state = :inside_comment
+          end
+        when :inside_element
+          if @m = CommentStart.match(@rest)
+            debug_state 'Comment'
+            things_read += 1
+            @already << @m.pre_match << @m.to_s
+            @rest = @m.post_match
+            self.state = :inside_comment
+          elsif @m = Tag.match(@rest)
+            debug_state 'Tag'
+            things_read += 1
+            self.state = :inside_element
+            handle_tag
+          elsif @m = CData.match(@rest)
+            debug_state 'CDATA'
+            @already << @m.pre_match
+            close_script_style if script_style?
+            @already << @m.to_s
+            @rest = @m.post_match
+            self.state = :inside_cdata
+          elsif @m = PartialTag.match(@rest)
+            debug_state 'PartialTag'
+            @already << @m.pre_match
+            @rest = @m.post_match
+            @partial_tag = @m.to_s
+            self.state = :inside_tag
+          elsif @m = EverythingElse.match(@rest)
+            debug_state 'EverythingElse'
+            @already << @m.pre_match << @m.to_s
+            @rest = @m.post_match
+            self.state = :inside_element
+          else
+            error "Malformed HTML: not complete: #{@rest.inspect}"
+          end
+        when :inside_tag
+          if @m = /^[^>]*>/.match(@rest)
+            @partial_tag << @m.to_s
+            @rest = @partial_tag + @m.post_match
+            @partial_tag = nil
+            self.state = :inside_element
+            if @m = Tag.match(@rest)
+              things_read += 1
+              handle_tag
+            end
+          else
+            @partial_tag << @rest
+            @rest = ""
+            self.state = :inside_tag
+          end
+        when :inside_cdata
+          if @m = CDataEnd.match(@rest)
+            self.state = :inside_element
+            @already << @m.pre_match << @m.to_s
+            @rest = @m.post_match
+            start_script_style if script_style?
+          else
+            @already << @rest
+            @rest = ""
+            self.state = :inside_cdata
+          end
+        else
+          raise "Bug bug: state = #{self.state.inspect}"
+        end
+
+        break if is_finished? && things_read > 0
+      end
+    end
+
+    def handle_tag
+      @already << @m.pre_match
+      @rest = @m.post_match
+
+      is_closing = !!@m[1]
+      tag = @m[2]
+      @first_tag ||= tag
+      attributes = @m[3].to_s
+
+      is_single = false
+      if attributes[-1, 1] == '/'
+        attributes = attributes[0, attributes.size - 1]
+        is_single = true
+      end
+
+      if TO_SANITIZE.include? tag
+        attributes.strip!
+        if attributes.size > 0
+          @already << '<%s %s />' % [tag, attributes]
+        else
+          @already << '<%s />' % [tag]
+        end
+      elsif is_closing
+        if @tag_stack.empty?
+          error "Malformed: closing tag #{tag.inspect} in empty list"
+        elsif @tag_stack.last != tag
+          error "Malformed: tag <#{tag}> closes <#{@tag_stack.last}>"
+        end
+
+        close_script_style if script_style?
+
+        @already << @m.to_s
+        @tag_stack.pop
+      else
+        @already << @m.to_s
+        @tag_stack.push(tag) unless is_single
+
+        start_script_style if script_style?
+      end
+    end
+
+    def stuff_you_read
+      @already
+    end
+
+    def is_finished?
+      self.state == :inside_element && @tag_stack.empty?
+    end
+
+    private
+
+    def debug_state(note)
+      my_debug "#{@state}: #{note}: #{@m.to_s.inspect}"
+    end
+
+    def my_debug(s)
+      #    puts "---" * 10 + "\n" + inspect + "\t>>>\t" + s
+    end
+
+    def error(s)
+      raise "Error: #{s} \n" + inspect, caller
+    end
+
+    def inspect
+      "HTML READER\n state=#{self.state} " +
+        "match=#{@m.to_s.inspect}\n" +
+        "Tag stack = #{@tag_stack.inspect} \n" +
+        "Before:\n" +
+        @already.gsub(/^/, '|') + "\n" +
+        "After:\n" +
+        @rest.gsub(/^/, '|') + "\n"
+    end
+
+    # Script and style tag handling
+    # -----------------------------
+    #
+    # XHTML, and XML parsers like REXML, require that certain characters be
+    # escaped within script or style tags. However, there are conflicts between
+    # documents served as XHTML vs HTML. So we need to be extra careful about
+    # how we escape these tags so they will even parse correctly. However, we
+    # also try to avoid adding that escaping unnecessarily.
+    #
+    # See http://dorward.me.uk/www/comments-cdata/ for a good explanation.
+
+    # Are we within a script or style tag?
+    def script_style?
+      %w(script style).include?(@tag_stack.last)
+    end
+
+    # Save our @already buffer elsewhere, and switch to using @already for the
+    # contents of this script or style tag.
+    def start_script_style
+      @before_already, @already = @already, ""
+    end
+
+    # Finish script or style tag content, wrapping it in CDATA if necessary,
+    # and add it to our original @already buffer.
+    def close_script_style
+      tag = @tag_stack.last
+
+      # See http://www.w3.org/TR/xhtml1/#C_4 for character sequences not allowed within an element body.
+      if @already =~ /<|&|\]\]>|--/
+        new_already = script_style_cdata_start(tag)
+        new_already << "\n" unless @already.start_with?("\n")
+        new_already << @already
+        new_already << "\n" unless @already.end_with?("\n")
+        new_already << script_style_cdata_end(tag)
+        @already = new_already
+      end
+      @before_already << @already
+      @already = @before_already
+    end
+
+    def script_style_cdata_start(tag)
+      (tag == 'script') ? "//<![CDATA[" : "/*<![CDATA[*/"
+    end
+
+    def script_style_cdata_end(tag)
+      (tag == 'script') ? "//]]>" : "/*]]>*/"
+    end
+  end
+end
diff --git a/lib/maruku/input/linesource.rb b/lib/maruku/input/linesource.rb
index e7adf3f..69b7e88 100644
--- a/lib/maruku/input/linesource.rb
+++ b/lib/maruku/input/linesource.rb
@@ -1,111 +1,91 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-module MaRuKu; module In; module Markdown; module BlockLevelParser
-
-# This represents a source of lines that can be consumed.
-#
-# It is the twin of CharSource.
-#
-	
-class LineSource
-	include MaRuKu::Strings
-	attr_reader :parent
-	
-	def initialize(lines, parent=nil, parent_offset=nil)
-		raise "NIL lines? " if not lines
-		@lines = lines
-		@lines_index = 0
-		@parent = parent
-		@parent_offset = parent_offset
-	end
-	
-	def cur_line()  @lines[@lines_index] end
-	def next_line() @lines[@lines_index+1] end
-		
-	def shift_line() 
-		raise "Over the rainbow" if @lines_index >= @lines.size 
-		l = @lines[@lines_index]
-		@lines_index += 1
-		return l
-	end
-	
-	def ignore_line
-		raise "Over the rainbow" if @lines_index >= @lines.size 
-		@lines_index += 1
-	end
-	
-	def describe
-		s = "At line #{original_line_number(@lines_index)}\n"
-		
-		context = 3 # lines
-		from = [@lines_index-context, 0].max
-		to   = [@lines_index+context, @lines.size-1].min
-		
-		for i in from..to
-			prefix = (i == @lines_index) ? '--> ' : '    ';
-			l = @lines[i]
-			s += "%10s %4s|%s" %
-				[@lines[i].md_type.to_s, prefix, l]
-				
-			s += "|\n"
-		end
-		
-#		if @parent 
-#			s << "Parent context is: \n"
-#			s << add_tabs(@parent.describe,1,'|')
-#		end
-		s
-	end
-	
-	def original_line_number(index)
-		if @parent
-			return index + @parent.original_line_number(@parent_offset)
-		else
-			1 + index
-		end
-	end
-	
-	def cur_index
-		@lines_index
-	end
-	
-	# Returns the type of next line as a string
-	# breaks at first :definition
-	def tell_me_the_future
-		s = ""; num_e = 0;
-		for i in @lines_index.. at lines.size-1
-			c = case @lines[i].md_type
-				when :text; "t"
-				when :empty; num_e+=1; "e"
-				when :definition; "d"
-				else "o"
-			end
-			s += c
-			break if c == "d" or num_e>1
-		end
-		s	
-	end
-	
-end # linesource
-
-end end end end # block
+module MaRuKu::In::Markdown::BlockLevelParser
+
+  # This represents a source of lines that can be consumed.
+  #
+  # It is the twin of CharSource.
+  #
+
+  class LineSource
+    attr_reader :parent
+
+    def initialize(lines, parent=nil, parent_offset=nil)
+      raise "NIL lines? " unless lines
+      @lines = lines.map {|l| l.kind_of?(MaRuKu::MDLine) ? l : MaRuKu::MDLine.new(l) }
+      @lines_index = 0
+      @parent = parent
+      @parent_offset = parent_offset
+    end
+
+    def cur_line
+      @lines[@lines_index]
+    end
+
+    def next_line
+      @lines[@lines_index + 1]
+    end
+
+    def shift_line
+      raise "Over the rainbow" if @lines_index >= @lines.size
+      l = @lines[@lines_index]
+      @lines_index += 1
+      l
+    end
+
+    def ignore_line
+      raise "Over the rainbow" if @lines_index >= @lines.size
+      @lines_index += 1
+    end
+
+    def describe
+      s = "At line #{original_line_number(@lines_index)}\n"
+
+      context = 3 # lines
+      from = [@lines_index - context, 0].max
+      to   = [@lines_index + context, @lines.size - 1].min
+
+      from.upto(to) do |i|
+        prefix = (i == @lines_index) ? '--> ' : '    ';
+        l = @lines[i]
+        s += "%10s %4s|%s" %
+          [@lines[i].md_type.to_s, prefix, l]
+
+        s += "|\n"
+      end
+
+      s
+    end
+
+    def original_line_number(index)
+      if @parent
+        index + @parent.original_line_number(@parent_offset)
+      else
+        1 + index
+      end
+    end
+
+    def cur_index
+      @lines_index
+    end
+
+    # Returns the type of next line as a string
+    # breaks at first :definition
+    def tell_me_the_future
+      s = ""
+      num_e = 0
+
+      @lines_index.upto(@lines.size - 1) do |i|
+        c = case @lines[i].md_type
+            when :text; "t"
+            when :empty; num_e += 1; "e"
+            when :definition; "d"
+            else "o"
+            end
+        s << c
+        break if c == "d" or num_e > 1
+      end
+      s
+    end
+
+  end # linesource
+end
 
diff --git a/lib/maruku/input/mdline.rb b/lib/maruku/input/mdline.rb
new file mode 100644
index 0000000..7073ecb
--- /dev/null
+++ b/lib/maruku/input/mdline.rb
@@ -0,0 +1,131 @@
+# This code does the classification of lines for block-level parsing.
+module MaRuKu
+
+  # Represents a single line in a Markdown source file, as produced by
+  # LineSource.
+  class MDLine < String
+    def md_type
+      @md_type ||= line_md_type
+    end
+
+    # Returns the number of leading spaces on this string,
+    # considering that a tab counts as {MaRuKu::Strings::TAB_SIZE} spaces.
+    #
+    # @param s [String]
+    # @return [Fixnum]
+    def number_of_leading_spaces
+      if self =~ /\A\s+/
+        spaces = $&
+        spaces.count(" ") + spaces.count("\t") * MaRuKu::Strings::TAB_SIZE
+      else
+        0
+      end
+    end
+
+    def gsub!(*args)
+      # Any in-place-modification method should reset the md_type
+      @md_type = nil
+      super
+    end
+
+    private
+
+    def line_md_type
+      # The order of evaluation is important (:text is a catch-all)
+      return :text           if self =~ /\A[a-zA-Z]/
+      return :empty          if self =~ /\A\s*\z/
+      return :footnote_text  if self =~ FootnoteText
+      return :ref_definition if self =~ LinkRegex || self =~ IncompleteLink
+      return :abbreviation   if self =~ Abbreviation
+      return :definition     if self =~ Definition
+      # I had a bug with emails and urls at the beginning of the
+      # line that were mistaken for raw_html
+      return :text           if self =~ /\A[ ]{0,3}#{EMailAddress}/
+      return :text           if self =~ /\A[ ]{0,3}<http:/
+      # raw html is like PHP Markdown Extra: at most three spaces before
+      return :xml_instr      if self =~ /\A\s*<\?/
+      return :raw_html       if self =~ %r{\A[ ]{0,3}</?\s*\w+}
+      return :raw_html       if self =~ /\A[ ]{0,3}<\!\-\-/
+      return :header1        if self =~ /\A(=)+/
+      return :header2        if self =~ /\A([-\s])+\z/
+      return :header3        if self =~ /\A(#)+\s*\S+/
+      # at least three asterisks/hyphens/underscores on a line, and only whitespace
+      return :hrule          if self =~ /\A(\s*[\*\-_]\s*){3,}\z/
+      return :ulist          if self =~ /\A[ ]{0,3}([\*\-\+])\s+.*/
+      return :olist          if self =~ /\A[ ]{0,3}\d+\.\s+.*/
+      return :code           if number_of_leading_spaces >= 4
+      return :quote          if self =~ /\A>/
+      return :ald            if self =~ AttributeDefinitionList
+      return :ial            if self =~ InlineAttributeList
+      return :text # else, it's just text
+    end
+  end
+
+  # MacRuby has trouble with commented regexes, so just put the expanded form
+  # in a comment.
+
+  # $1 = id   $2 = attribute list
+  AttributeDefinitionList = /\A\s{0,3}\{([\w\s]+)\}:\s*(.*?)\s*\z/
+  #
+  InlineAttributeList = /\A\s{0,3}\{([:#\.].*?)\}\s*\z/
+  # Example:
+  #     ^:blah blah
+  #     ^: blah blah
+  #     ^   : blah blah
+  Definition = /\A[ ]{0,3}:\s*(\S.*)\z/
+  # %r{
+  #   ^ # begin of line
+  #   [ ]{0,3} # up to 3 spaces
+  #   : # colon
+  #   \s* # whitespace
+  #   (\S.*) # the text    = $1
+  #   $ # end of line
+  # }x
+
+  # Example:
+  #     *[HTML]: Hyper Text Markup Language
+  Abbreviation = /\A[ ]{0,3}\*\[([^\]]+)\]:\s*(\S.*\S)*\s*\z/
+  # %r{
+  #   ^  # begin of line
+  #   [ ]{0,3} # up to 3 spaces
+  #   \* # one asterisk
+  #   \[ # opening bracket
+  #   ([^\]]+) # any non-closing bracket:  id = $1
+  #   \] # closing bracket
+  #   :  # colon
+  #   \s* # whitespace
+  #   (\S.*\S)* #           definition=$2
+  #   \s* # strip this whitespace
+  #   $   # end of line
+  # }x
+
+  FootnoteText = /\A[ ]{0,3}\[(\^.+)\]:\s*(\S.*)?\z/
+  # %r{
+  #   ^  # begin of line
+  #   [ ]{0,3} # up to 3 spaces
+  #   \[(\^.+)\]: # id = $1 (including '^')
+  #   \s*(\S.*)?$    # text = $2 (not obb.)
+  # }x
+
+  # This regex is taken from BlueCloth sources
+  # Link defs are in the form: ^[id]: \n? url "optional title"
+  LinkRegex = /\A[ ]{0,3}\[([^\[\]]+)\]:[ ]*<?([^>\s]+)>?[ ]*(?:(?:(?:"([^"]+)")|(?:'([^']+)')|(?:\(([^\(\)]+)\)))\s*(.+)?)?/
+  #%r{
+  # ^[ ]{0,3}\[([^\[\]]+)\]:    # id = $1
+  #   [ ]*
+  # <?([^>\s]+)>?       # url = $2
+  #   [ ]*
+  # (?: # Titles are delimited by "quotes" or (parens).
+  #   (?:(?:"([^"]+)")|(?:'([^']+)')|(?:\(([^\(\)]+)\))) # title = $3, $4, or $5
+  #   \s*(.+)? # stuff = $6
+  # )?  # title is optional
+  #}x
+
+  IncompleteLink = /\A[ ]{0,3}\[([^\[\]]+?)\]:\s*\z/
+
+  # Table syntax: http://michelf.ca/projects/php-markdown/extra/#table
+  # | -------------:| ------------------------------ |
+  TableSeparator = /\A(?>\|?\s*\:?\-+\:?\s*\|?)+?\z/
+
+  EMailAddress = /<([^:@>]+?@[^:@>]+?)>/
+end
diff --git a/lib/maruku/input/parse_block.rb b/lib/maruku/input/parse_block.rb
index c676c29..6d12917 100644
--- a/lib/maruku/input/parse_block.rb
+++ b/lib/maruku/input/parse_block.rb
@@ -1,615 +1,729 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
 module MaRuKu; module In; module Markdown; module BlockLevelParser
 
-	include Helpers
-	include MaRuKu::Strings
-	include MaRuKu::In::Markdown::SpanLevelParser
-
-	class BlockContext < Array
-		def describe
-			n = 5
-			desc = size > n ? self[-n,n] : self
-			"Last #{n} elements: "+
-			desc.map{|x| "\n -" + x.inspect}.join
-		end
-	end
-	
-	# Splits the string and calls parse_lines_as_markdown
-	def parse_text_as_markdown(text)
-		lines =  split_lines(text)
-		src = LineSource.new(lines)
-		return parse_blocks(src)
-	end
-	
-	# Input is a LineSource
-	def parse_blocks(src)
-		output = BlockContext.new
-		
-		# run state machine
-		while src.cur_line
-			
-			next if check_block_extensions(src, output, src.cur_line)
-			
-#  Prints detected type (useful for debugging)
-#			puts "#{src.cur_line.md_type}|#{src.cur_line}"
-			case src.cur_line.md_type
-				when :empty; 
-					output.push :empty
-					src.ignore_line
-				when :ial
-					m =  InlineAttributeList.match src.shift_line
-					content = m[1] ||  "" 
-#					puts "Content: #{content.inspect}"
-					src2 = CharSource.new(content, src)
-					interpret_extension(src2, output, [nil])
-				when :ald
-					output.push read_ald(src)
-				when :text
-					# paragraph, or table, or definition list
-					read_text_material(src, output)
-				when :header2, :hrule
-					# hrule
-					src.shift_line
-					output.push md_hrule()
-				when :header3
-					output.push read_header3(src)
-				when :ulist, :olist
-					list_type = src.cur_line.md_type == :ulist ? :ul : :ol
-					li = read_list_item(src)
-					# append to current list if we have one
-					if output.last.kind_of?(MDElement) && 
-						output.last.node_type == list_type then
-						output.last.children << li
-					else
-						output.push md_el(list_type, [li])
-					end
-				when :quote;    output.push read_quote(src)
-				when :code;     e = read_code(src); output << e if e
-				when :raw_html; e = read_raw_html(src); output << e if e
-
-				when :footnote_text;   output.push read_footnote_text(src)
-				when :ref_definition;  
-					if src.parent && (src.cur_index == 0)
-						read_text_material(src, output)
-					else
-						read_ref_definition(src, output)
-					end
-				when :abbreviation;    output.push read_abbreviation(src)
-				when :xml_instr;       read_xml_instruction(src, output)
-				when :metadata;        
-					maruku_error "Please use the new meta-data syntax: \n"+
-					"  http://maruku.rubyforge.org/proposal.html\n", src
-					src.ignore_line
-				else # warn if we forgot something
-					md_type = src.cur_line.md_type
-					line = src.cur_line
-					maruku_error "Ignoring line '#{line}' type = #{md_type}", src
-					src.shift_line
-			end
-		end
-
-		merge_ial(output, src, output)
-		output.delete_if {|x| x.kind_of?(MDElement) &&
-			x.node_type == :ial}
-		
-		# get rid of empty line markers
-		output.delete_if {|x| x == :empty}
-		# See for each list if we can omit the paragraphs and use li_span
-		# TODO: do this after
-		output.each do |c| 
-			# Remove paragraphs that we can get rid of
-			if [:ul,:ol].include? c.node_type 
-				if c.children.all? {|li| !li.want_my_paragraph} then
-					c.children.each do |d|
-						d.node_type = :li_span
-						d.children = d.children[0].children 
-					end
-				end
-			end 
-			if c.node_type == :definition_list
-				if c.children.all?{|defi| !defi.want_my_paragraph} then
-					c.children.each do |definition| 
-						definition.definitions.each do |dd|
-							dd.children = dd.children[0].children 
-						end
-					end
-				end
-			end 
-		end
-		
-		output
-	end
-	
-	def read_text_material(src, output)
-		if src.cur_line =~ MightBeTableHeader and 
-			(src.next_line && src.next_line =~ TableSeparator)
-			output.push read_table(src)
-		elsif [:header1,:header2].include? src.next_line.md_type
-			output.push read_header12(src)
-		elsif eventually_comes_a_def_list(src)
-		 	definition = read_definition(src)
-			if output.last.kind_of?(MDElement) && 
-				output.last.node_type == :definition_list then
-				output.last.children << definition
-			else
-				output.push md_el(:definition_list, [definition])
-			end
-		else # Start of a paragraph
-			output.push read_paragraph(src)
-		end
-	end
-	
-	
-	def read_ald(src)
-		if (l=src.shift_line) =~ AttributeDefinitionList
-			id = $1;   al=$2;
-			al = read_attribute_list(CharSource.new(al,src), context=nil, break_on=[nil])
-			self.ald[id] = al;
-			return md_ald(id, al)
-		else
-			maruku_error "Bug Bug:\n#{l.inspect}"
-			return nil
-		end
-	end
-		
-	# reads a header (with ----- or ========)
-	def read_header12(src)
-		line = src.shift_line.strip
-		al = nil
-		# Check if there is an IAL
-		if new_meta_data? and line =~ /^(.*)\{(.*)\}\s*$/
-			line = $1.strip
-			ial = $2
-			al  = read_attribute_list(CharSource.new(ial,src), context=nil, break_on=[nil])
-		end
-		text = parse_lines_as_span [ line ]
-		level = src.cur_line.md_type == :header2 ? 2 : 1;  
-		src.shift_line
-		return md_header(level, text, al)
-	end
-
-	# reads a header like '#### header ####'	
-	def read_header3(src)
-		line = src.shift_line.strip
-		al = nil
-		# Check if there is an IAL
-		if new_meta_data? and line =~ /^(.*)\{(.*)\}\s*$/
-			line = $1.strip
-			ial = $2
-			al  = read_attribute_list(CharSource.new(ial,src), context=nil, break_on=[nil])
-		end
-		level = num_leading_hashes(line)
-		text = parse_lines_as_span [strip_hashes(line)] 
-		return md_header(level, text, al)
-	end
-
-	def read_xml_instruction(src, output)
-		m = /^\s*<\?((\w+)\s*)?(.*)$/.match src.shift_line
-		raise "BugBug" if not m
-		target = m[2] || ''
-		code = m[3]
-		until code =~ /\?>/
-			code += "\n"+src.shift_line
-		end
-		if not code =~ (/\?>\s*$/)
-			garbage = (/\?>(.*)$/.match(code))[1]
-			maruku_error "Trailing garbage on last line: #{garbage.inspect}:\n"+
-				add_tabs(code, 1, '|'), src
-		end
-		code.gsub!(/\?>\s*$/, '')
-		
-		if target == 'mrk' && MaRuKu::Globals[:unsafe_features]
-			result = safe_execute_code(self, code)	
-			if result
-				if result.kind_of? String
-					raise "Not expected"
-				else
-					output.push(*result)
-				end
-			end
-		else
-			output.push md_xml_instr(target, code)
-		end
-	end
-	
-	def read_raw_html(src)
-		h = HTMLHelper.new
-		begin 
-			h.eat_this(l=src.shift_line)
-#			puts "\nBLOCK:\nhtml -> #{l.inspect}"
-			while src.cur_line and not h.is_finished? 
-				l=src.shift_line
-#				puts "html -> #{l.inspect}"
-				h.eat_this "\n"+l
-			end
-		rescue Exception => e
-			ex = e.inspect + e.backtrace.join("\n")
-			maruku_error "Bad block-level HTML:\n#{add_tabs(ex,1,'|')}\n", src
-		end
-		if not (h.rest =~ /^\s*$/)
-			maruku_error "Could you please format this better?\n"+
-				"I see that #{h.rest.inspect} is left after the raw HTML.", src
-		end
-		raw_html = h.stuff_you_read
-		
-		return md_html(raw_html)
-	end
-	
-	def read_paragraph(src)
-		lines = [src.shift_line]
-		while src.cur_line 
-			# :olist does not break
-			case t = src.cur_line.md_type
-				when :quote,:header3,:empty,:ref_definition,:ial #,:xml_instr,:raw_html
-					break
-				when :olist,:ulist
-					break if src.next_line.md_type == t
-			end
-			break if src.cur_line.strip.size == 0			
-			break if [:header1,:header2].include? src.next_line.md_type
-			break if any_matching_block_extension?(src.cur_line) 
-			
-			lines << src.shift_line
-		end
-#		dbg_describe_ary(lines, 'PAR')
-		children = parse_lines_as_span(lines, src)
-
-		return md_par(children)
-	end
-	
-	# Reads one list item, either ordered or unordered.
-	def read_list_item(src)
-		parent_offset = src.cur_index
-		
-		item_type = src.cur_line.md_type
-		first = src.shift_line
-
-		indentation = spaces_before_first_char(first)
-		break_list = [:ulist, :olist, :ial]
-		# Ugly things going on inside `read_indented_content`
-		lines, want_my_paragraph = 
-			read_indented_content(src,indentation, break_list, item_type)
-
-		# add first line
-			# Strip first '*', '-', '+' from first line
-			stripped = first[indentation, first.size-1]
-		lines.unshift stripped
-		
-		# dbg_describe_ary(lines, 'LIST ITEM ')
-
-		src2 = LineSource.new(lines, src, parent_offset)
-		children = parse_blocks(src2)
-		with_par = want_my_paragraph || (children.size>1)
-		
-		return md_li(children, with_par)
-	end
-
-	def read_abbreviation(src)
-		if not (l=src.shift_line) =~ Abbreviation
-			maruku_error "Bug: it's Andrea's fault. Tell him.\n#{l.inspect}"
-		end
-		
-		abbr = $1
-		desc = $2
-		
-		if (not abbr) or (abbr.size==0)
-			maruku_error "Bad abbrev. abbr=#{abbr.inspect} desc=#{desc.inspect}"
-		end
-		
-		self.abbreviations[abbr] = desc
-		
-		return md_abbr_def(abbr, desc)
-	end
-	
-	def read_footnote_text(src)
-		parent_offset = src.cur_index
-			
-		first = src.shift_line
-		
-		if not first =~ FootnoteText 
-			maruku_error "Bug (it's Andrea's fault)"
-		end
-		
-		id = $1
-		text = $2
-
-		# Ugly things going on inside `read_indented_content`
-		indentation = 4 #first.size-text.size
-		
-#		puts "id =_#{id}_; text=_#{text}_ indent=#{indentation}"
-		
-		break_list = [:footnote_text, :ref_definition, :definition, :abbreviation]
-		item_type = :footnote_text
-		lines, want_my_paragraph = 
-			read_indented_content(src,indentation, break_list, item_type)
-
-		# add first line
-		if text && text.strip != "" then lines.unshift text end
-		
-#		dbg_describe_ary(lines, 'FOOTNOTE')
-		src2 = LineSource.new(lines, src, parent_offset)
-		children = parse_blocks(src2)
-		
-		e = md_footnote(id, children)
-		self.footnotes[id] = e
-		return e
-	end
-
-
-	# This is the only ugly function in the code base.
-	# It is used to read list items, descriptions, footnote text
-	def read_indented_content(src, indentation, break_list, item_type)
-		lines =[]
-		# collect all indented lines
-		saw_empty = false; saw_anything_after = false
-		while src.cur_line 
-#			puts "Reading indent = #{indentation} #{src.cur_line.inspect}"
-			#puts "#{src.cur_line.md_type} #{src.cur_line.inspect}"
-			if src.cur_line.md_type == :empty
-				saw_empty = true
-				lines << src.shift_line
-				next
-			end
-		
-			# after a white line
-			if saw_empty
-				# we expect things to be properly aligned
-				if (ns=number_of_leading_spaces(src.cur_line)) < indentation
-					#puts "breaking for spaces, only #{ns}: #{src.cur_line}"
-					break
-				end
-				saw_anything_after = true
-			else
-#				if src.cur_line[0] != ?\ 
-					break if break_list.include? src.cur_line.md_type
-#				end
-#				break if src.cur_line.md_type != :text
-			end
-		
-
-			stripped = strip_indent(src.shift_line, indentation)
-			lines << stripped
-
-			#puts "Accepted as #{stripped.inspect}"
-		
-			# You are only required to indent the first line of 
-			# a child paragraph.
-			if stripped.md_type == :text
-				while src.cur_line && (src.cur_line.md_type == :text)
-					lines << strip_indent(src.shift_line, indentation)
-				end
-			end
-		end
-
-		want_my_paragraph = saw_anything_after || 
-			(saw_empty && (src.cur_line  && (src.cur_line.md_type == item_type))) 
-	
-#		dbg_describe_ary(lines, 'LI')
-		# create a new context 
-	
-		while lines.last && (lines.last.md_type == :empty)
-			lines.pop
-		end
-		
-		return lines, want_my_paragraph
-	end
-
-	
-	def read_quote(src)
-		parent_offset = src.cur_index
-			
-		lines = []
-		# collect all indented lines
-		while src.cur_line && src.cur_line.md_type == :quote
-			lines << unquote(src.shift_line)
-		end
-#		dbg_describe_ary(lines, 'QUOTE')
-
-		src2 = LineSource.new(lines, src, parent_offset)
-		children = parse_blocks(src2)
-		return md_quote(children)
-	end
-
-	def read_code(src)
-		# collect all indented lines
-		lines = []
-		while src.cur_line && ([:code, :empty].include? src.cur_line.md_type)
-			lines << strip_indent(src.shift_line, 4)
-		end
-		
-		#while lines.last && (lines.last.md_type == :empty )
-		while lines.last && lines.last.strip.size == 0
-			lines.pop 
-		end
-
-		while lines.first && lines.first.strip.size == 0
-			lines.shift 
-		end
-		
-		return nil if lines.empty?
-
-		source = lines.join("\n")
-		
-#		dbg_describe_ary(lines, 'CODE')
-
-		return md_codeblock(source)
-	end
-
-	# Reads a series of metadata lines with empty lines in between
-	def read_metadata(src)
-		hash = {}
-		while src.cur_line 
-			case src.cur_line.md_type
-				when :empty;  src.shift_line
-				when :metadata; hash.merge! parse_metadata(src.shift_line)
-				else break
-			end
-		end
-		hash
-	end
-	
-		
-	def read_ref_definition(src, out)	
-		line = src.shift_line
-		
-		
-		# if link is incomplete, shift next line
-		if src.cur_line && !([:footnote_text, :ref_definition, :definition, :abbreviation].include? src.cur_line.md_type) && 
-			([1,2,3].include? number_of_leading_spaces(src.cur_line) ) 
-			line += " "+ src.shift_line
-		end
-		
-#		puts "total= #{line}"
-		
-		match = LinkRegex.match(line)
-		if not match
-			maruku_error "Link does not respect format: '#{line}'"
-			return
-		end
-		
-		id = match[1]; url = match[2]; title = match[3]; 
-		id = sanitize_ref_id(id)
-		
-		hash = self.refs[id] = {:url=>url,:title=>title}
-		
-		stuff=match[4]
-		
-		if stuff
-			stuff.split.each do |couple|
-#					puts "found #{couple}"
-				k, v = couple.split('=')
-				v ||= ""
-				if v[0,1]=='"' then v = v[1, v.size-2] end
-#					puts "key:_#{k}_ value=_#{v}_"
-				hash[k.to_sym] = v
-			end
-		end
-#			puts hash.inspect
-		
-		out.push md_ref_def(id, url, meta={:title=>title})
-	end
-	
-	def split_cells(s)
-#		s.strip.split('|').select{|x|x.strip.size>0}.map{|x|x.strip}
-# changed to allow empty cells
-		s.strip.split('|').select{|x|x.size>0}.map{|x|x.strip}
-	end
-
-	def read_table(src)
-		head = split_cells(src.shift_line).map{|s| md_el(:head_cell, parse_lines_as_span([s])) }
-			
-		separator=split_cells(src.shift_line)
-
-		align = separator.map { |s|  s =~ Sep
-			if $1 and $2 then :center elsif $2 then :right else :left end }
-				
-		num_columns = align.size
-		
-		if head.size != num_columns
-			maruku_error "Table head does not have #{num_columns} columns: \n#{head.inspect}"
-			tell_user "I will ignore this table."
-			# XXX try to recover
-			return md_br()
-		end
-				
-		rows = []
-		
-		while src.cur_line && src.cur_line =~ /\|/
-			row = split_cells(src.shift_line).map{|s|
-				md_el(:cell, parse_lines_as_span([s]))}
-			if head.size != num_columns
-				maruku_error  "Row does not have #{num_columns} columns: \n#{row.inspect}"
-				tell_user "I will ignore this table."
-				# XXX try to recover
-				return md_br()
-			end
-			rows << row
-		end
-
-		children = (head+rows).flatten
-		return md_el(:table, children, {:align => align})
-	end
-	
-	# If current line is text, a definition list is coming
-	# if 1) text,empty,[text,empty]*,definition
-	
-	def eventually_comes_a_def_list(src)
-		future = src.tell_me_the_future
-		ok = future =~ %r{^t+e?d}x
-#		puts "future: #{future} - #{ok}"
-		ok
-	end
-	
-		
-	def read_definition(src)
-		# Read one or more terms
-		terms = []
-		while  src.cur_line &&  src.cur_line.md_type == :text
-			terms << md_el(:definition_term, parse_lines_as_span([src.shift_line]))
-		end
-#		dbg_describe_ary(terms, 'DT')
-
-		want_my_paragraph = false
-
-		raise "Chunky Bacon!" if not src.cur_line
-
-		# one optional empty
-		if src.cur_line.md_type == :empty
-			want_my_paragraph = true
-			src.shift_line
-		end
-		
-		raise "Chunky Bacon!" if src.cur_line.md_type != :definition
-		
-		# Read one or more definitions
-		definitions = []
-		while src.cur_line && src.cur_line.md_type == :definition
-			parent_offset = src.cur_index
-				
-			first = src.shift_line
-			first =~ Definition
-			first = $1
-			
-			# I know, it's ugly!!!
-
-			lines, w_m_p = 
-				read_indented_content(src,4, [:definition], :definition)
-			want_my_paragraph ||= w_m_p
-		
-			lines.unshift first
-			
-#			dbg_describe_ary(lines, 'DD')
-			src2 = LineSource.new(lines, src, parent_offset)
-			children = parse_blocks(src2)
-			definitions << md_el(:definition_data, children)
-		end
-		
-		return md_el(:definition, terms+definitions, { 	
-			:terms => terms, 
-			:definitions => definitions, 
-			:want_my_paragraph => want_my_paragraph})
-	end
-end # BlockLevelParser
-end # MaRuKu
-end
-end
\ No newline at end of file
+  include Helpers
+  include MaRuKu::Strings
+  include MaRuKu::In::Markdown::SpanLevelParser
+
+  class BlockContext < Array
+    def describe
+      n = 5
+      desc = size > n ? self[-n, n] : self
+      "Last #{n} elements: " +
+        desc.map {|x| "\n -" + x.inspect }.join
+    end
+  end
+
+  # Splits the string and calls parse_lines_as_markdown
+  def parse_text_as_markdown(text)
+    lines =  split_lines(text)
+    src = LineSource.new(lines)
+    parse_blocks(src)
+  end
+
+  # Input is a LineSource
+  def parse_blocks(src)
+    output = BlockContext.new
+
+    # run state machine
+    while src.cur_line
+      next if check_block_extensions(src, output, src.cur_line)
+
+      md_type = src.cur_line.md_type
+
+      # Prints detected type (useful for debugging)
+      #puts "parse_blocks #{md_type}|#{src.cur_line}"
+      case md_type
+      when :empty
+        output << :empty
+        src.ignore_line
+      when :ial
+        m = InlineAttributeList.match src.shift_line
+        content = m[1] || ""
+        src2 = CharSource.new(content, src)
+        interpret_extension(src2, output)
+      when :ald
+        output << read_ald(src)
+      when :text
+        # paragraph, or table, or definition list
+        read_text_material(src, output)
+      when :header2, :hrule
+        # hrule
+        src.shift_line
+        output << md_hrule
+      when :header3
+        output << read_header3(src)
+      when :ulist, :olist
+        list_type = (md_type == :ulist) ? :ul : :ol
+        li = read_list_item(src)
+        # append to current list if we have one
+        if output.last.kind_of?(MDElement) &&
+            output.last.node_type == list_type then
+          output.last.children << li
+        else
+          output << md_el(list_type, li)
+        end
+      when :quote
+        output << read_quote(src)
+      when :code
+        e = read_code(src)
+        output << e if e
+      when :raw_html
+        # More extra hacky stuff - if there's more than just HTML, we either wrap it
+        # in a paragraph or break it up depending on whether it's an inline element or not
+        e = read_raw_html(src)
+        unless e.empty?
+          if e.first.parsed_html &&
+              (first_node_name = e.first.parsed_html.first_node_name) &&
+              HTML_INLINE_ELEMS.include?(first_node_name) &&
+              !%w(svg math).include?(first_node_name)
+            content = [e.first]
+            if e.size > 1
+              content.concat(e[1].children)
+            end
+            output << md_par(content)
+          else
+            output.concat(e)
+          end
+        end
+      when :footnote_text
+        output << read_footnote_text(src)
+      when :ref_definition
+        if src.parent && src.cur_index == 0
+          read_text_material(src, output)
+        else
+          read_ref_definition(src, output)
+        end
+      when :abbreviation
+        output << read_abbreviation(src)
+      when :xml_instr
+        read_xml_instruction(src, output)
+      else # unhandled line type at this level
+        # Just treat it as raw text
+        read_text_material(src, output)
+      end
+    end
+
+    merge_ial(output, src, output)
+    output.delete_if do |x|
+      # Strip out IAL
+      (x.kind_of?(MDElement) && x.node_type == :ial) ||
+      # get rid of empty line markers
+      x == :empty
+    end
+
+    # See for each list if we can omit the paragraphs
+    # TODO: do this after
+    output.each do |c|
+      # Remove paragraphs that we can get rid of
+      if [:ul, :ol].include?(c.node_type) && c.children.none?(&:want_my_paragraph)
+        c.children.each do |d|
+          if d.children.first && d.children.first.node_type == :paragraph
+            d.children = d.children.first.children + d.children[1..-1]
+          end
+        end
+      elsif c.node_type == :definition_list && c.children.none?(&:want_my_paragraph)
+        c.children.each do |definition|
+          definition.definitions.each do |dd|
+            if dd.children.first.node_type == :paragraph
+              dd.children = dd.children.first.children + dd.children[1..-1]
+            end
+          end
+        end
+      end
+    end
+
+    output
+  end
+
+  def read_text_material(src, output)
+    if src.cur_line.include?('|') && # if contains a pipe, it could be a table header
+        src.next_line &&
+        src.next_line.rstrip =~ TableSeparator
+      output << read_table(src)
+    elsif src.next_line && [:header1, :header2].include?(src.next_line.md_type)
+      output << read_header12(src)
+    elsif eventually_comes_a_def_list(src)
+      definition = read_definition(src)
+      if output.last.kind_of?(MDElement) &&
+          output.last.node_type == :definition_list then
+        output.last.children << definition
+      else
+        output << md_el(:definition_list, definition)
+      end
+    else # Start of a paragraph
+      output.concat read_paragraph(src)
+    end
+  end
+
+  def read_ald(src)
+    if (l = src.shift_line) =~ AttributeDefinitionList
+      id = $1
+      al = read_attribute_list(CharSource.new($2, src))
+      self.ald[id] = al;
+      md_ald(id, al)
+    else
+      maruku_error "Bug Bug:\n#{l.inspect}"
+      nil
+    end
+  end
+
+  # reads a header (with ----- or ========)
+  def read_header12(src)
+    line = src.shift_line.strip
+    al = nil
+    # Check if there is an IAL
+    if new_meta_data? and line =~ /^(.*?)\{(.*?)\}\s*$/
+      line = $1.strip
+      ial = $2
+      al = read_attribute_list(CharSource.new(ial, src))
+    end
+    text = parse_span line
+    if text.empty?
+      text = "{#{ial}}"
+      al = nil
+    end
+    level = src.cur_line.md_type == :header2 ? 2 : 1;
+    src.shift_line
+    md_header(level, text, al)
+  end
+
+  # reads a header like '#### header ####'
+  def read_header3(src)
+    line = src.shift_line.strip
+    al = nil
+    # Check if there is an IAL
+    if new_meta_data? and line =~ /^(.*?)\{(.*?)\}\s*$/
+      line = $1.strip
+      ial = $2
+      al = read_attribute_list(CharSource.new(ial, src))
+    end
+    level = line[/^#+/].size
+    text = parse_span line.gsub(/\A#+|#+\z/, '')
+    if text.empty?
+      text = "{#{ial}}"
+      al = nil
+    end
+    md_header(level, text, al)
+  end
+
+  def read_xml_instruction(src, output)
+    m = /^\s*<\?((\w+)\s*)?(.*)$/.match src.shift_line
+    raise "BugBug" unless m
+    target = m[2] || ''
+    code = m[3]
+    until code.include?('?>')
+      code << "\n" << src.shift_line
+    end
+    unless code =~ /\?>\s*$/
+      garbage = (/\?>(.*)$/.match(code))[1]
+      maruku_error "Trailing garbage on last line: #{garbage.inspect}:\n" +
+        code.gsub(/^/, '|'), src
+    end
+    code.gsub!(/\?>\s*$/, '')
+
+    if target == 'mrk' && MaRuKu::Globals[:unsafe_features]
+      result = safe_execute_code(self, code)
+      if result
+        if result.kind_of? String
+          raise "Not expected"
+        else
+          output.push(*result)
+        end
+      end
+    else
+      output << md_xml_instr(target, code)
+    end
+  end
+
+  def read_raw_html(src)
+    extra_line = nil
+    h = HTMLHelper.new
+    begin
+      l = src.shift_line
+      h.eat_this(l)
+      #     puts "\nBLOCK:\nhtml -> #{l.inspect}"
+      while src.cur_line && !h.is_finished?
+        l = src.shift_line
+        #       puts "html -> #{l.inspect}"
+        h.eat_this "\n" + l
+      end
+    rescue => e
+      maruku_error "Bad block-level HTML:\n#{e.inspect.gsub(/^/, '|')}\n", src
+    end
+    unless h.rest =~ /^\s*$/
+      extra_line = h.rest
+    end
+    raw_html = h.stuff_you_read
+
+    is_inline = HTML_INLINE_ELEMS.include?(h.first_tag)
+
+    if extra_line
+      remainder = is_inline ? parse_span(extra_line) : parse_text_as_markdown(extra_line)
+      if extra_line.start_with?(' ')
+        remainder[0] = ' ' + remainder[0] if remainder[0].is_a?(String)
+      end
+      is_inline ? [md_html(raw_html), md_par(remainder)] : [md_html(raw_html)] + remainder
+    else
+      [md_html(raw_html)]
+    end
+  end
+
+  def read_paragraph(src)
+    lines = [src.shift_line]
+    while src.cur_line
+      # :olist does not break
+      case t = src.cur_line.md_type
+      when :quote, :header3, :empty, :ref_definition, :ial, :xml_instr
+        break
+      when :olist, :ulist
+        break if !src.next_line || src.next_line.md_type == t
+      end
+      break if src.cur_line.strip.empty?
+      break if src.next_line && [:header1, :header2].include?(src.next_line.md_type)
+      break if any_matching_block_extension?(src.cur_line)
+
+      lines << src.shift_line
+    end
+    children = parse_span(lines, src)
+
+    pick_apart_non_inline_html(children)
+  end
+
+  # If there are non-inline HTML tags in the paragraph, break them out into
+  # their own elements and make paragraphs out of everything else.
+  def pick_apart_non_inline_html(children)
+    output = []
+    para_children = []
+
+    children.each do |child|
+      if element_is_non_inline_html?(child)
+        unless para_children.empty?
+          # Fix up paragraphs before non-inline elements having an extra space
+          last_child = para_children.last
+          if last_child.is_a?(String) && !last_child.empty?
+            last_child.replace last_child[0..-2]
+          end
+
+          output << md_par(para_children)
+          para_children = []
+        end
+        output << child
+      else
+        para_children << child
+      end
+    end
+
+    unless para_children.empty?
+      output << md_par(para_children)
+    end
+
+    output
+  end
+
+  # Is the given element an HTML element whose root is not an inline element?
+  def element_is_non_inline_html?(elem)
+    if elem.is_a?(MDElement) && elem.node_type == :raw_html && elem.parsed_html
+      first_node_name = elem.parsed_html.first_node_name
+      first_node_name && !HTML_INLINE_ELEMS.include?(elem.parsed_html.first_node_name)
+    else
+      false
+    end
+  end
+
+  # Reads one list item, either ordered or unordered.
+  def read_list_item(src)
+    parent_offset = src.cur_index
+
+    item_type = src.cur_line.md_type
+    first = src.shift_line
+
+    indentation, ial = spaces_before_first_char(first)
+    al = read_attribute_list(CharSource.new(ial, src)) if ial
+    ial_offset = ial ? ial.length + 3 : 0
+    lines, want_my_paragraph = read_indented_content(src, indentation, [], item_type, ial_offset)
+
+    # in case there is a second line and this line starts a new list, format it.
+    if !lines.empty? && [:ulist, :olist].include?(MaRuKu::MDLine.new(lines.first).md_type)
+      lines.unshift ""
+    end
+
+    # add first line
+    # Strip first '*', '-', '+' from first line
+    first_changed = first.gsub(/([^\t]*)(\t)/) { $1 + " " * (TAB_SIZE - $1.length % TAB_SIZE) }
+    stripped = first_changed[indentation, first_changed.size - 1]
+    lines.unshift stripped
+    src2 = LineSource.new(lines, src, parent_offset)
+    children = parse_blocks(src2)
+
+    md_li(children, want_my_paragraph, al)
+  end
+
+  def read_abbreviation(src)
+    unless (l = src.shift_line) =~ Abbreviation
+      maruku_error "Bug: it's Andrea's fault. Tell him.\n#{l.inspect}"
+    end
+
+    abbr = $1
+    desc = $2
+
+    if !abbr || abbr.empty?
+      maruku_error "Bad abbrev. abbr=#{abbr.inspect} desc=#{desc.inspect}"
+    end
+
+    self.abbreviations[abbr] = desc
+
+    md_abbr_def(abbr, desc)
+  end
+
+  def read_footnote_text(src)
+    parent_offset = src.cur_index
+
+    first = src.shift_line
+
+    unless first =~ FootnoteText
+      maruku_error "Bug (it's Andrea's fault)"
+    end
+
+    id = $1
+    text = $2 || ''
+
+    indentation = 4 #first.size-text.size
+
+    #   puts "id =_#{id}_; text=_#{text}_ indent=#{indentation}"
+
+    break_list = [:footnote_text, :ref_definition, :definition, :abbreviation]
+    item_type = :footnote_text
+    lines, _ = read_indented_content(src, indentation, break_list, item_type)
+
+    # add first line
+    lines.unshift text unless text.strip.empty?
+
+    src2 = LineSource.new(lines, src, parent_offset)
+    children = parse_blocks(src2)
+
+    e = md_footnote(id, children)
+    self.footnotes[id] = e
+    e
+  end
+
+
+  # This is the only ugly function in the code base.
+  # It is used to read list items, descriptions, footnote text
+  def read_indented_content(src, indentation, break_list, item_type, ial_offset=0)
+    lines = []
+    # collect all indented lines
+    saw_empty = false
+    saw_anything_after = false
+    break_list = Array(break_list)
+    len = indentation - ial_offset
+
+    while src.cur_line
+      num_leading_spaces = src.cur_line.number_of_leading_spaces
+      break if num_leading_spaces < len && ![:text, :empty].include?(src.cur_line.md_type)
+
+      line = strip_indent(src.cur_line, indentation)
+      md_type = line.md_type
+
+      if md_type == :empty
+        saw_empty = true
+        lines << line
+        src.shift_line
+        next
+      end
+
+      # Unquestioningly grab anything that's deeper-indented
+      if md_type != :code && num_leading_spaces > len
+        lines << line
+        src.shift_line
+        next
+      end
+
+      # after a white line
+      if saw_empty
+        # we expect things to be properly aligned
+        break if num_leading_spaces < len
+        saw_anything_after = true
+      else
+        break if break_list.include?(md_type)
+      end
+
+      lines << line
+      src.shift_line
+
+      # You are only required to indent the first line of
+      # a child paragraph.
+      if md_type == :text
+        while src.cur_line && src.cur_line.md_type == :text
+          lines << strip_indent(src.shift_line, indentation)
+        end
+      end
+    end
+
+    # TODO fix this
+    want_my_paragraph = saw_anything_after ||
+      (saw_empty && src.cur_line && src.cur_line.md_type == item_type)
+
+    # create a new context
+
+    while lines.last && lines.last.md_type == :empty
+      lines.pop
+    end
+
+    return lines, want_my_paragraph
+  end
+
+
+  def read_quote(src)
+    parent_offset = src.cur_index
+
+    lines = []
+    # collect all indented lines
+    while src.cur_line && src.cur_line.md_type == :quote
+      lines << unquote(src.shift_line)
+    end
+
+    src2 = LineSource.new(lines, src, parent_offset)
+    children = parse_blocks(src2)
+    md_quote(children)
+  end
+
+  def read_code(src)
+    # collect all indented lines
+    lines = []
+    while src.cur_line && [:code, :empty].include?(src.cur_line.md_type)
+      lines << strip_indent(src.shift_line, 4)
+    end
+
+    #while lines.last && (lines.last.md_type == :empty )
+    while lines.last && lines.last.strip.size == 0
+      lines.pop
+    end
+
+    while lines.first && lines.first.strip.size == 0
+      lines.shift
+    end
+
+    return nil if lines.empty?
+
+    source = lines.join("\n")
+
+    md_codeblock(source)
+  end
+
+  def read_ref_definition(src, out)
+    line = src.shift_line
+
+    # if link is incomplete, shift next line
+    if src.cur_line &&
+        ![:footnote_text, :ref_definition, :definition, :abbreviation].include?(src.cur_line.md_type) &&
+        (1..3).include?(src.cur_line.number_of_leading_spaces)
+      line << " " << src.shift_line
+    end
+
+    match = LinkRegex.match(line)
+    unless match
+      maruku_error "Link does not respect format: '#{line}'" and return
+    end
+
+    id = match[1]
+    url = match[2]
+    title = match[3] || match[4] || match[5]
+    id = sanitize_ref_id(id)
+
+    hash = self.refs[id] = {
+      :url => url,
+      :title => title
+    }
+
+    stuff = (match[6] || '')
+    stuff.split.each do |couple|
+      k, v = couple.split('=')
+      v ||= ""
+      v = v[1..-2] if v.start_with?('"') # strip quotes
+      hash[k.to_sym] = v
+    end
+
+    out << md_ref_def(id, url, :title => title)
+  end
+
+  def split_cells(s, allowBlank = false)
+    if allowBlank
+      if /^[|].*[|]$/ =~ s # handle the simple and decorated table cases
+        s.split('|', -1)[1..-2]   # allow blank cells, but only keep the inner elements of the cells
+      elsif /^.*[|]$/ =~ s
+        s.split('|', -1)[0..-2]   # allow blank cells, but only keep the inner elements of the cells
+      else
+        s.split('|', -1)
+      end
+    else
+      s.split('|').reject(&:empty?).map(&:strip)
+    end
+  end
+
+  def read_table(src)
+    head = split_cells(src.shift_line).map do |s|
+      md_el(:head_cell, parse_span(s))
+    end
+
+    separator = split_cells(src.shift_line)
+
+    align = separator.map do |s|
+      # ex: :-------------------:
+      # If the separator starts and ends with a colon,
+      # center the cell. If it's on the right, right-align,
+      # otherwise left-align.
+      starts = s.start_with? ':'
+      ends = s.end_with? ':'
+      if s.empty? # blank
+        nil
+      elsif starts && ends
+        :center
+      elsif ends
+        :right
+      else
+        :left
+      end
+    end
+
+    align.pop if align[-1].nil? # trailing blank
+    num_columns = align.size
+
+    head.pop if head.size == num_columns + 1 && head[-1].al.size == 0 # trailing blank
+
+    if head.size != num_columns
+      maruku_error "Table head does not have #{num_columns} columns: \n#{head.inspect}"
+      tell_user "I will ignore this table."
+      # XXX try to recover
+      return md_br
+    end
+
+    rows = []
+    while src.cur_line && src.cur_line.include?('|')
+      row = []
+      colCount = 0
+      colspan = 1
+      currElem = nil
+      currIdx = 0
+      split_cells(src.shift_line, true).map do |s|
+        if s.empty?
+          # empty cells increase the colspan of the previous cell
+          found = false
+          colspan +=  1
+          al = (currElem &&currElem.al) || AttributeList.new
+          if al.size > 0
+            elem = find_colspan(al)
+            if elem != nil
+              elem[1] = colspan.to_s
+              found = true
+            end
+          end
+          al.push(["colspan", colspan.to_s]) unless found # also handles the case of and empty attribute list
+        else
+          colspan = 1
+          row[currIdx] = md_el(:cell, parse_span(s))
+          currElem = row[currIdx]
+          currIdx += 1
+        end
+      end
+
+      #
+      # sanity check - make sure the current row has the right number of columns (including spans)
+      #                If not, dump the table and return a break
+      #
+      num_columns = count_columns(row)
+      if num_columns == head.size + 1 && row[-1].al.size == 0 #trailing blank cell
+        row.pop
+        num_columns -= 1
+      end
+      if head.size != num_columns
+        maruku_error  "Row does not have #{head.size} columns: \n#{row.inspect} - #{num_columns}"
+        tell_user "I will ignore this table."
+        # XXX need to recover
+        return md_br
+      end
+      rows << row
+    end
+    rows.unshift(head) # put the header row on the processed table
+    md_el(:table, rows, { :align => align })
+  end
+
+  #
+  # count the actual number of elements in a row taking into account colspans
+  #
+  def count_columns(row)
+    colCount = 0
+
+    row.each do |cell|
+      if cell.al && cell.al.size > 0
+        al = find_colspan(cell.al)
+        if al != nil
+          colCount += al[1].to_i
+        else
+          colCount += 1
+        end
+      else
+        colCount += 1
+      end
+    end
+
+    colCount
+  end
+
+  #
+  # Search an attribute list looking for a colspan
+  #
+  def find_colspan(al)
+    al.find {|alElem| alElem[0] == "colspan" }
+  end
+
+  # If current line is text, a definition list is coming
+  # if 1) text,empty,[text,empty]*,definition
+  def eventually_comes_a_def_list(src)
+    src.tell_me_the_future =~ %r{^t+e?d}x
+  end
+
+  def read_definition(src)
+    # Read one or more terms
+    terms = []
+    while src.cur_line && src.cur_line.md_type == :text
+      terms << md_el(:definition_term, parse_span(src.shift_line))
+    end
+
+    want_my_paragraph = false
+
+    raise "Chunky Bacon!" unless src.cur_line
+
+    # one optional empty
+    if src.cur_line.md_type == :empty
+      want_my_paragraph = true
+      src.shift_line
+    end
+
+    raise "Chunky Bacon!" unless src.cur_line.md_type == :definition
+
+    # Read one or more definitions
+    definitions = []
+    while src.cur_line && src.cur_line.md_type == :definition
+      parent_offset = src.cur_index
+
+      first = src.shift_line
+      first =~ Definition
+      first = $1
+
+      lines, w_m_p = read_indented_content(src, 4, :definition, :definition)
+      want_my_paragraph ||= w_m_p
+
+      lines.unshift first
+
+      src2 = LineSource.new(lines, src, parent_offset)
+      children = parse_blocks(src2)
+      definitions << md_el(:definition_data, children)
+    end
+
+    md_el(:definition, terms + definitions, {
+            :terms => terms,
+            :definitions => definitions,
+            :want_my_paragraph => want_my_paragraph
+          })
+  end
+end end end end
diff --git a/lib/maruku/input/parse_doc.rb b/lib/maruku/input/parse_doc.rb
index f4a4909..82777a2 100644
--- a/lib/maruku/input/parse_doc.rb
+++ b/lib/maruku/input/parse_doc.rb
@@ -1,37 +1,16 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-require 'iconv'
-
-
-module MaRuKu; module In; module Markdown; module BlockLevelParser
-		
-	def parse_doc(s)
-		# FIXME \r\n => \n
-		meta2 =  parse_email_headers(s)
-		data = meta2[:data]
-		meta2.delete :data
-		
-		self.attributes.merge! meta2
-		
+require 'strscan'
+require 'cgi'
+
+module MaRuKu::In::Markdown::BlockLevelParser
+
+  def parse_doc(s)
+    # Remove BOM if it is present
+    s = s.sub(/^\xEF\xBB\xBF/u, '')
+    meta2 = parse_email_headers(s)
+    data = meta2.delete :data
+
+    self.attributes.merge! meta2
+
 =begin maruku_doc
 Attribute: encoding
 Scope:     document
@@ -39,50 +18,42 @@ Summary:   Encoding for the document.
 
 If the `encoding` attribute is specified, then the content
 will be converted from the specified encoding to UTF-8.
-
-Conversion happens using the `iconv` library.
 =end
 
-		enc = self.attributes[:encoding]
-		self.attributes.delete :encoding
-		if enc && enc.downcase != 'utf-8'
-			converted = Iconv.new('utf-8', enc).iconv(data)
-			
-#			puts "Data: #{data.inspect}: #{data}"
-#			puts "Conv: #{converted.inspect}: #{converted}"
-			
-			data = converted
-		end
-		
-		@children = parse_text_as_markdown(data)
-		
-		if true #markdown_extra? 
-			self.search_abbreviations
-			self.substitute_markdown_inside_raw_html
-		end
-		
-		toc = create_toc
-
-		# use title if not set
-		if not self.attributes[:title] and toc.header_element
-			title = toc.header_element.to_s
-			self.attributes[:title]  = title
-#			puts "Set document title to #{title}"
-		end
-		
-		# save for later use
-		self.toc = toc
-		
-		# Now do the attributes magic
-		each_element do |e|
-			# default attribute list
-			if default = self.ald[e.node_type.to_s]
-				expand_attribute_list(default, e.attributes)
-			end
-			expand_attribute_list(e.al, e.attributes)
-#			puts "#{e.node_type}: #{e.attributes.inspect}"
-		end
-	
+    enc = self.attributes.delete(:encoding) || 'utf-8'
+    if enc.downcase != 'utf-8'
+      # Switch to ruby 1.9 String#encode
+      # with backward 1.8 compatibility
+      if data.respond_to?(:encode!)
+        data.encode!('UTF-8', enc)
+      else
+        require 'iconv'
+        data = Iconv.new('utf-8', enc).iconv(data)
+      end
+    end
+
+    @children = parse_text_as_markdown(data)
+
+    if markdown_extra?
+      self.search_abbreviations
+      self.substitute_markdown_inside_raw_html
+    end
+
+    self.toc = create_toc
+
+    # use title if not set
+    self.attributes[:title] ||= toc.header_element.children.join if toc.header_element
+
+    # Now do the attributes magic
+    each_element do |e|
+      # default attribute list
+      if default = self.ald[e.node_type.to_s]
+        expand_attribute_list(default, e.attributes)
+      end
+      expand_attribute_list(e.al, e.attributes)
+#     puts "#{e.node_type}: #{e.attributes.inspect}"
+    end
+
 =begin maruku_doc
 Attribute: unsafe_features
 Scope:     global
@@ -91,144 +62,101 @@ Summary:   Enables execution of XML instructions.
 Disabled by default because of security concerns.
 =end
 
-		if Maruku::Globals[:unsafe_features]
-			self.execute_code_blocks
-			# TODO: remove executed code blocks
-		end
-	end
-	
-	# Expands an attribute list in an Hash
-	def expand_attribute_list(al, result)
-		al.each do |k, v|
-			case k
-			when :class
-				if not result[:class]
-					result[:class] = v
-				else
-					result[:class] += " " + v
-				end
-			when :id; result[:id] = v
-			when :ref; 
-				if self.ald[v]
-					already = (result[:expanded_references] ||= [])
-					if not already.include?(v)
-						already.push v
-						expand_attribute_list(self.ald[v], result)
-					else
-						already.push  v
-						maruku_error "Circular reference between labels.\n\n"+
-						"Label #{v.inspect} calls itself via recursion.\nThe recursion is "+
-							(already.map{|x| x.inspect}.join(' => ')) 
-					end
-				else
-					if not result[:unresolved_references]
-						result[:unresolved_references] = v
-					else
-						result[:unresolved_references] << " #{v}"
-					end
-					
-				#	$stderr.puts "Unresolved reference #{v.inspect} (avail: #{self.ald.keys.inspect})"
-					result[v.to_sym] = true
-				end
-			else
-				result[k.to_sym]=v
-			end
-		end
-	end
-
-	def safe_execute_code(object, code)
-		begin
-			return object.instance_eval(code)
-		rescue Exception => e
-			maruku_error "Exception while executing this:\n"+
-				add_tabs(code, 1, ">")+
-				"\nThe error was:\n"+
-				add_tabs(e.inspect+"\n"+e.caller.join("\n"), 1, "|")
-		rescue RuntimeError => e
-			maruku_error "2: Exception while executing this:\n"+
-				add_tabs(code, 1, ">")+
-				"\nThe error was:\n"+
-				add_tabs(e.inspect, 1, "|")
-		rescue SyntaxError => e
-			maruku_error "2: Exception while executing this:\n"+
-				add_tabs(code, 1, ">")+
-				"\nThe error was:\n"+
-				add_tabs(e.inspect, 1, "|")
-		end
-		nil
-	end
-	
-	def execute_code_blocks
-		self.each_element(:xml_instr) do |e|
-			if e.target == 'maruku'
-				result = safe_execute_code(e, e.code)
-				if result.kind_of?(String)
-					puts "Result is : #{result.inspect}"
-				end
-			end
-		end
-	end
-	
-	def search_abbreviations
-		self.abbreviations.each do |abbrev, title|
-			reg = Regexp.new(Regexp.escape(abbrev))
-			self.replace_each_string do |s|
-				# bug if many abbreviations are present (agorf)
-				if m = reg.match(s)
-					e = md_abbr(abbrev.dup, title ? title.dup : nil)
-					[m.pre_match, e, m.post_match]
-				else
-					s
-				end
-			end
-		end
-	end
-	
-	include REXML
-	# (PHP Markdown extra) Search for elements that have
-	# markdown=1 or markdown=block defined
-	def substitute_markdown_inside_raw_html
-		self.each_element(:raw_html) do |e|
-			doc = e.instance_variable_get :@parsed_html
-			if doc # valid html
-				# parse block-level markdown elements in these HTML tags
-				block_tags = ['div']
-
-				# use xpath to find elements with 'markdown' attribute
-				XPath.match(doc, "//*[attribute::markdown]" ).each do |e|
-#					puts "Found #{e}"
-					# should we parse block-level or span-level?
-					
-					how = e.attributes['markdown']
-					parse_blocks = (how == 'block') || block_tags.include?(e.name)
-					               
-					# Select all text elements of e
-					XPath.match(e, "//text()" ).each { |original_text| 
-						s = original_text.value.strip
-						if s.size > 0
-
-					#	    puts "Parsing #{s.inspect} as blocks: #{parse_blocks}  (#{e.name}, #{e.attributes['markdown']})  "
-
-							el = md_el(:dummy,
-							 	parse_blocks ? parse_text_as_markdown(s) :
-							                  parse_lines_as_span([s]) )
-							p = original_text.parent
-							el.children_to_html.each do |x|
-								p.insert_before(original_text, x)
-							end
-							p.delete(original_text)
-							
-						end
-					}
-					
-					
-          # remove 'markdown' attribute
-          e.delete_attribute 'markdown'
-          
-				end
-				
-			end
-		end
-	end
-	
-end end end end
+    if Maruku::Globals[:unsafe_features]
+      self.execute_code_blocks
+      # TODO: remove executed code blocks
+    end
+  end
+
+  # Expands an attribute list in an Hash
+  def expand_attribute_list(al, result)
+    al.each do |k, v|
+      case k
+      when :class
+        if result[:class]
+          result[:class] << " " << v
+        else
+          result[:class] = v
+        end
+      when :id
+        result[:id] = v
+      when :ref
+        if self.ald[v]
+          already = (result[:expanded_references] ||= [])
+          if !already.include?(v)
+            already << v
+            expand_attribute_list(self.ald[v], result)
+          else
+            already << v
+            maruku_error "Circular reference between labels.\n\n" +
+            "Label #{v.inspect} calls itself via recursion.\nThe recursion is " +
+              already.map(&:inspect).join(' => ')
+          end
+        else
+          if result[:unresolved_references]
+            result[:unresolved_references] << " " << v
+          else
+            result[:unresolved_references] = v
+          end
+
+          # $stderr.puts "Unresolved reference #{v.inspect} (avail: #{self.ald.keys.inspect})"
+          result[v.to_sym] = true
+        end
+      else
+        result[k.to_sym] = v
+      end
+    end
+  end
+
+  def safe_execute_code(object, code)
+    begin
+      object.instance_eval(code)
+    rescue StandardError, ScriptError => e
+      maruku_error "Exception while executing this:\n" +
+        code.gsub(/^/, ">") +
+        "\nThe error was:\n" +
+        (e.inspect + "\n" + e.caller.join("\n")).gsub(/^/, "|")
+      nil
+    end
+  end
+
+  def execute_code_blocks
+    each_element(:xml_instr) do |e|
+      if e.target == 'maruku'
+        result = safe_execute_code(e, e.code)
+        if result.kind_of?(String)
+          puts "Result is : #{result.inspect}"
+        end
+      end
+    end
+  end
+
+  def search_abbreviations
+    abbreviations.each do |abbrev, title|
+      reg = Regexp.new(Regexp.escape(abbrev))
+      replace_each_string do |s|
+        # bug if many abbreviations are present (agorf)
+        p = StringScanner.new(s)
+        a = []
+        until p.eos?
+          o = ''
+          o << p.getch until p.scan(reg) or p.eos?
+          a << o unless o.empty?
+          a << md_abbr(abbrev.dup, title ? title.dup : nil) if p.matched == abbrev
+        end
+        a
+      end
+    end
+  end
+
+  # (PHP Markdown extra) Search for elements that have
+  # markdown=1 or markdown=block defined
+  def substitute_markdown_inside_raw_html
+    each_element(:raw_html) do |e|
+      html = e.parsed_html
+      next unless html
+
+      html.process_markdown_inside_elements(self)
+    end
+  end
+end
diff --git a/lib/maruku/input/parse_span.rb b/lib/maruku/input/parse_span.rb
new file mode 100644
index 0000000..b914608
--- /dev/null
+++ b/lib/maruku/input/parse_span.rb
@@ -0,0 +1,657 @@
+module MaRuKu::In::Markdown::SpanLevelParser
+  include MaRuKu::Helpers
+
+  EscapedCharInText = '\\`*_{}[]()#.!|:+->'.split(//)
+  EscapedCharInQuotes = EscapedCharInText + ["'", '"']
+
+  EscapedCharInInlineCode = ['\\', '`']
+
+  IgnoreWikiLinks = MaRuKu::Globals[:ignore_wikilinks]
+
+  def parse_span(string, parent=nil)
+    string = Array(string).join("\n") unless string.kind_of? String
+    src = MaRuKu::In::Markdown::SpanLevelParser::CharSource.new(string, parent)
+    read_span(src, EscapedCharInText, [nil])
+  end
+
+  # This is the main loop for reading span elements
+  #
+  # It's long, but not *complex* or difficult to understand.
+  #
+  #
+  def read_span(src, escaped, exit_on_chars=nil, exit_on_strings=nil)
+    escaped = Array(escaped)
+    con = SpanContext.new
+    c = d = nil
+    while true
+      c = src.cur_char
+
+      # This is only an optimization which cuts 50% of the time used.
+      # (but you can't use a-zA-z in exit_on_chars)
+      if c && c =~ /a-zA-Z0-9/
+        con.push_char src.shift_char
+        next
+      end
+
+      break if Array(exit_on_chars).include?(c)
+      if Array(exit_on_strings).any? {|x| src.cur_chars_are x }
+        # Special case: bold nested in italic
+        break unless !(['*', '_'] & Array(exit_on_strings)).empty? &&
+          ['**', '__'].include?(src.cur_chars(2)) &&
+          !['***', '___'].include?(src.cur_chars(3))
+      end
+
+      # check if there are extensions
+      next if check_span_extensions(src, con)
+
+      case c = src.cur_char
+      when ' '
+        if src.cur_chars_are "  \n"
+          src.ignore_chars(3)
+          con.push_element md_br
+          next
+        else
+          src.ignore_char
+          con.push_space
+        end
+      when "\n", "\t"
+        src.ignore_char
+        con.push_space
+      when '`'
+        read_inline_code(src, con)
+      when '<'
+        # It could be:
+        # 1) HTML "<div ..."
+        # 2) HTML "<!-- ..."
+        # 3) url "<http:// ", "<ftp:// ..."
+        # 4) email "<andrea at ... ", "<mailto:andrea at ..."
+        # 5) on itself! "a < b  "
+        # 6) Start of <<guillemettes>>
+
+        case d = src.next_char
+        when '<'  # guillemettes
+          src.ignore_chars(2)
+          con.push_char '<'
+          con.push_char '<'
+        when '!'
+          if src.cur_chars_are '<!--'
+            read_inline_html(src, con)
+          else
+            con.push_char src.shift_char
+          end
+        when '?'
+          read_xml_instr_span(src, con)
+        when ' ', "\t"
+          con.push_char src.shift_char
+        else
+          if src.next_matches(/<mailto:/) ||
+              src.next_matches(/<[\w\.]+\@/)
+            read_email_el(src, con)
+          elsif src.next_matches(/<\w+:/)
+            read_url_el(src, con)
+          elsif src.next_matches(/<\w/)
+            #puts "This is HTML: #{src.cur_chars(20)}"
+            read_inline_html(src, con)
+          else
+            #puts "This is NOT HTML: #{src.cur_chars(20)}"
+            con.push_char src.shift_char
+          end
+        end
+      when "\\"
+        d = src.next_char
+        if d == "'"
+          src.ignore_chars(2)
+          con.push_element md_entity('apos')
+        elsif d == '"'
+          src.ignore_chars(2)
+          con.push_element md_entity('quot')
+        elsif escaped.include? d
+          src.ignore_chars(2)
+          con.push_char d
+        else
+          con.push_char src.shift_char
+        end
+      when '['
+        if markdown_extra? && src.next_char == '^'
+          read_footnote_ref(src,con)
+        elsif IgnoreWikiLinks && src.next_char == '['
+          con.push_char src.shift_char
+          con.push_char src.shift_char
+        else
+          read_link(src, con)
+        end
+      when '!'
+        if src.next_char == '['
+          read_image(src, con)
+        else
+          con.push_char src.shift_char
+        end
+      when '&'
+        # named references
+        if m = src.read_regexp(/\&(\w+);/)
+          con.push_element md_entity(m[1])
+          # numeric
+        elsif m = src.read_regexp(/\&\#(x)?(\w+);/)
+          num = m[1] ? m[2].hex : m[2].to_i
+          con.push_element md_entity(num)
+        else
+          con.push_char src.shift_char
+        end
+      when '*'
+        if !src.next_char
+          maruku_error "Opening * as last char.", src, con, 'Treating as literal'
+          con.push_char src.shift_char
+        else
+          follows = src.cur_chars(4)
+          if follows =~ /^\*\*\*[^\s\*]/
+            con.push_element read_emstrong(src, '***')
+          elsif follows  =~ /^\*\*[^\s\*]/
+            con.push_element read_strong(src, '**')
+          elsif follows =~ /^\*[^\s\*]/
+            con.push_element read_em(src, '*')
+          else # * is just a normal char
+            con.push_char src.shift_char
+          end
+        end
+      when '_'
+        if !src.next_char
+          maruku_error "Opening _ as last char", src, con, 'Treating as literal'
+          con.push_char src.shift_char
+        else
+          # we don't want "mod_ruby" to start an emphasis
+          # so we start one only if
+          # 1) there's nothing else in the span (first char)
+          # or 2) the last char was a space
+          # or 3) the current string is empty
+          #if con.elements.empty? ||
+          if con.is_end?
+            # also, we check the next characters
+            follows = src.cur_chars(4)
+            if  follows =~ /^\_\_\_[^\s\_]/
+              con.push_element read_emstrong(src, '___')
+            elsif follows  =~ /^\_\_[^\s\_]/
+              con.push_element read_strong(src, '__')
+            elsif follows =~ /^\_[^\s\_]/
+              con.push_element read_em(src, '_')
+            else # _ is just a normal char
+              con.push_char src.shift_char
+            end
+          else
+            # _ is just a normal char
+            con.push_char src.shift_char
+          end
+        end
+      when '{' # extension
+        if ['#', '.', ':'].include? src.next_char
+          src.ignore_char # {
+          interpret_extension(src, con, '}')
+          src.ignore_char # }
+        else
+          con.push_char src.shift_char
+        end
+      when nil
+        maruku_error( ("Unclosed span (waiting for %s" +
+                       "#{exit_on_strings.inspect})") %
+                      [ exit_on_chars ? "#{exit_on_chars.inspect} or" : "" ],
+                      src, con)
+        break
+      else # normal text
+        con.push_char src.shift_char
+      end # end case
+    end # end while true
+
+    con.push_string_if_present
+
+    # Assign IAL to elements
+    merge_ial(con.elements, src, con)
+
+    # Remove leading space
+    if (s = con.elements.first).kind_of? String
+      if s[0, 1] == ' '
+        con.elements[0] = s[1..-1]
+      end
+      con.elements.shift if s.empty?
+    end
+
+    # Remove final spaces
+    if (s = con.elements.last).kind_of? String
+      s.chop! if s[-1, 1] == ' '
+      con.elements.pop if s.empty?
+    end
+
+    educate(con.elements)
+  end
+
+
+  def read_xml_instr_span(src, con)
+    src.ignore_chars(2) # starting <?
+
+    # read target <?target code... ?>
+    target = if m = src.read_regexp(/^(\w+)/)
+               m[1]
+             else
+               # XML instructions are invalid without a target
+               ''
+             end
+
+    delim = "?>"
+
+    code = read_simple(src, nil, nil, delim)
+
+    src.ignore_chars delim.size
+
+    code = (code || "").strip
+    con.push_element md_xml_instr(target, code)
+  end
+
+  # Start: cursor on character **after** '{'
+  # End: curson on '}' or EOF
+  def interpret_extension(src, con, break_on_chars=nil)
+    case src.cur_char
+    when ':'
+      src.ignore_char # :
+      extension_meta(src, con, break_on_chars)
+    when '#', '.'
+      extension_meta(src, con, break_on_chars)
+    else
+      stuff = read_simple(src, '}', break_on_chars)
+      if stuff =~ /^(\w+\s|[^\w])/
+        extension_id = $1.strip
+
+        maruku_recover "I don't know what to do with extension '#{extension_id}'\n" +
+          "I will treat this:\n\t{#{stuff}} \n as meta-data.\n", src, con
+      else
+        maruku_recover "I will treat this:\n\t{#{stuff}} \n as meta-data.\n", src, con
+      end
+      extension_meta(src, con, break_on_chars)
+    end
+  end
+
+  def extension_meta(src, con, break_on_chars=nil)
+    if m = src.read_regexp(/([^\s\:\"\'}]+?):/)
+      name = m[1]
+      al = read_attribute_list(src, con, break_on_chars)
+      self.doc.ald[name] = al
+      con.push md_ald(name, al)
+    else
+      al = read_attribute_list(src, con, break_on_chars)
+      con.push md_ial(al)
+    end
+  end
+
+  def read_url_el(src,con)
+    src.ignore_char # leading <
+    url = read_simple(src, nil, '>')
+    src.ignore_char # closing >
+
+    con.push_element md_url(url)
+  end
+
+  def read_email_el(src,con)
+    src.ignore_char # leading <
+    mail = read_simple(src, nil, '>')
+    src.ignore_char # closing >
+
+    address = mail.gsub(/^mailto:/, '')
+    con.push_element md_email(address)
+  end
+
+  def read_url(src, break_on)
+    if ["'", '"'].include? src.cur_char
+      maruku_error 'Invalid char for url', src
+    end
+
+    url = read_simple(src, nil, break_on) || ''
+
+    if url[0, 1] == '<' && url[-1, 1] == '>'
+      url = url[1, url.size-2]
+    end
+
+    return nil if url.empty?
+    url
+  end
+
+
+  def read_quoted_or_unquoted(src, con, escaped, exit_on_chars)
+    case src.cur_char
+    when "'", '"'
+      read_quoted(src, con)
+    else
+      read_simple(src, escaped, exit_on_chars, nil, false)
+    end
+  end
+
+  # Tries to read a quoted value. If stream does not
+  # start with ' or ", returns nil.
+  def read_quoted(src, con)
+    case src.cur_char
+    when "'", '"'
+      quote_char = src.shift_char # opening quote
+      string = read_simple(src, EscapedCharInQuotes, quote_char)
+      src.ignore_char # closing quote
+      string
+    else
+      nil
+    end
+  end
+
+  # Reads a simple string (no formatting) until one of exit_on_chars,
+  # while escaping the escaped.
+  # If the string is empty, it returns nil.
+  # By default, raises on error if the string terminates unexpectedly. This can be
+  # by setting the last argument to false.
+  def read_simple(src, escaped, exit_on_chars=nil, exit_on_strings=nil, warn=true)
+    text = ""
+    escaped = Array(escaped)
+    exit_on_chars = Array(exit_on_chars)
+    exit_on_strings = Array(exit_on_strings)
+    while true
+      c = src.cur_char
+
+      break if exit_on_chars.include?(c)
+      break if exit_on_strings.any? {|x| src.cur_chars_are x }
+
+      case c
+      when nil
+        if warn
+          maruku_error "String finished while reading (break on " +
+            "#{(exit_on_chars + exit_on_strings).inspect})" +
+            " already read: #{text.inspect}", src
+        end
+        break
+      when "\\"
+        d = src.next_char
+        if escaped.include? d
+          src.ignore_chars(2)
+          text << d
+        else
+          text << src.shift_char
+        end
+      else
+        text << src.shift_char
+      end
+    end
+
+    text.empty? ? nil : text
+  end
+
+  def read_em(src, delim)
+    src.ignore_char
+    children = read_span(src, EscapedCharInText, nil, delim)
+    src.ignore_char
+    md_em(children)
+  end
+
+  def read_strong(src, delim)
+    src.ignore_chars(2)
+    children = read_span(src, EscapedCharInText, nil, delim)
+    src.ignore_chars(2)
+    md_strong(children)
+  end
+
+  def read_emstrong(src, delim)
+    src.ignore_chars(3)
+    children = read_span(src, EscapedCharInText, nil, delim)
+    src.ignore_chars(3)
+    md_emstrong(children)
+  end
+
+  # Reads a bracketed id "[refid]". Consumes also both brackets.
+  def read_ref_id(src, con)
+    src.ignore_char # [
+    if m = src.read_regexp(/([^\]]*?)\]/)
+      m[1]
+    else
+      nil
+    end
+  end
+
+  def read_footnote_ref(src,con)
+    ref = read_ref_id(src,con)
+    con.push_element md_foot_ref(ref)
+  end
+
+  def read_inline_html(src, con)
+    h = HTMLHelper.new
+    begin
+      # This is our current buffer in the context
+      next_stuff = src.current_remaining_buffer
+
+      consumed = 0
+      while true
+        if consumed >= next_stuff.size
+          maruku_error "Malformed HTML starting at #{next_stuff.inspect}", src, con
+          break
+        end
+
+        h.eat_this next_stuff[consumed].chr
+        consumed += 1
+        break if h.is_finished?
+      end
+      src.ignore_chars(consumed)
+      con.push_element md_html(h.stuff_you_read)
+    rescue => e
+      maruku_error "Bad html: \n" +
+        e.inspect.gsub(/^/, '>'), src, con, "I will try to continue after bad HTML."
+      con.push_char src.shift_char
+    end
+  end
+
+  def read_inline_code(src, con)
+    # Count the number of ticks
+    num_ticks = 0
+    while src.cur_char == '`'
+      num_ticks += 1
+      src.ignore_char
+    end
+    # We will read until this string
+    end_string = "`" * num_ticks
+
+    # Try to handle empty single-ticks
+    if num_ticks > 1 && !src.next_matches(/.*#{Regexp.escape(end_string)}/)
+      con.push_element(end_string) and return
+    end
+
+    code = read_simple(src, nil, nil, end_string)
+
+    # We didn't find a closing batch!
+    if !code || src.cur_char != '`'
+      con.push_element(end_string + (code || '')) and return
+    end
+
+    #   puts "Now I expects #{num_ticks} ticks: #{src.cur_chars(10).inspect}"
+    src.ignore_chars num_ticks
+
+    # Ignore at most one space
+    if num_ticks > 1 && code[0, 1] == ' '
+      code = code[1..-1]
+    end
+
+    # drop last space
+    if num_ticks > 1 && code[-1, 1] == ' '
+      code = code[0..-2]
+    end
+
+    #   puts "Read `` code: #{code.inspect}; after: #{src.cur_chars(10).inspect} "
+    con.push_element md_code(code)
+  end
+
+  def read_link(src, con)
+    # we read the string and see what happens
+    src.ignore_char # opening bracket
+    children = read_span(src, EscapedCharInText, ']')
+    src.ignore_char # closing bracket
+
+    # ignore space
+    if src.cur_char == ' ' && ['[', '('].include?(src.next_char)
+      src.shift_char
+    end
+
+    case src.cur_char
+    when '('
+      src.ignore_char # opening (
+      src.consume_whitespace
+      url = read_url(src, [' ', "\t", ")"]) || ''
+
+      src.consume_whitespace
+      title = nil
+      if src.cur_char != ')' # we have a title
+        quote_char = src.cur_char
+        title = read_quoted(src, con)
+
+        if not title
+          maruku_error 'Must quote title', src, con
+        else
+          # Tries to read a title with quotes: ![a](url "ti"tle")
+          # this is the most ugly thing in Markdown
+          unless src.next_matches(/\s*\)/)
+            # if there is not a closing par ), then read
+            # the rest and guess it's title with quotes
+            rest = read_simple(src, nil, ')', nil)
+            # chop the closing char
+            rest.chop!
+            title << quote_char << rest
+          end
+        end
+      end
+      src.consume_whitespace
+      closing = src.shift_char # closing )
+      if closing != ')'
+        maruku_error 'Unclosed link', src, con, "No closing ): I will not create" +
+          " the link for #{children.inspect}"
+        con.push_elements children
+        return
+      end
+      con.push_element md_im_link(children, url, title)
+    when '[' # link ref
+      ref_id = read_ref_id(src, con)
+      if ref_id
+        con.push_element md_link(children, ref_id)
+      else
+        maruku_error "Could not read ref_id", src, con, "I will not create the link for " +
+          "#{children.inspect}"
+        con.push_elements children
+        return
+      end
+    else # empty [link]
+      con.push_element md_link(children, nil)
+    end
+  end # read link
+
+  def read_image(src, con)
+    src.ignore_chars(2) # opening "!["
+    alt_text = read_span(src, EscapedCharInText, ']')
+    src.ignore_char # closing bracket
+    # ignore space
+    if src.cur_char == ' ' && ['[', '('].include?(src.next_char)
+      src.ignore_char
+    end
+    case src.cur_char
+    when '('
+      src.ignore_char # opening (
+      src.consume_whitespace
+      url = read_url(src, [' ', "\t", ')'])
+      unless url
+        maruku_error "Could not read url from #{src.cur_chars(10).inspect}", src, con
+      end
+      src.consume_whitespace
+      title = nil
+      if src.cur_char != ')' # we have a title
+        quote_char = src.cur_char
+        title = read_quoted(src, con)
+        if !title
+          maruku_error 'Must quote title', src, con
+        else
+          # Tries to read a title with quotes: ![a](url "ti"tle")
+          # this is the most ugly thing in Markdown
+          if !src.next_matches(/\s*\)/)
+            # if there is not a closing par ), then read
+            # the rest and guess it's title with quotes
+            rest = read_simple(src, nil, ')', nil)
+            # chop the closing char
+            rest.chop!
+            title << quote_char << rest
+          end
+        end
+      end
+      src.consume_whitespace
+      closing = src.shift_char # closing )
+      if closing != ')'
+        maruku_error "Unclosed link: '#{closing}'" +
+          " Read url=#{url.inspect} title=#{title.inspect}", src, con
+      end
+      con.push_element md_im_image(alt_text, url, title)
+    when '[' # link ref
+      ref_id = read_ref_id(src, con)
+      if !ref_id # TODO: check around
+        maruku_error 'Reference not closed.', src, con
+        ref_id = ""
+      end
+
+      con.push_element md_image(alt_text, ref_id)
+    else # no stuff
+      ref_id = alt_text.join
+      con.push_element md_image(alt_text, ref_id)
+    end
+  end # read link
+
+  class SpanContext
+    # Read elements
+    attr_accessor :elements
+
+    def initialize
+      @elements = []
+      @cur_string = ''
+    end
+
+    def push_element(e)
+      raise "Only MDElement and String, please. You pushed #{e.class}: #{e.inspect} " unless
+        e.kind_of?(String) || e.kind_of?(MaRuKu::MDElement)
+
+      push_string_if_present
+
+      @elements << e
+    end
+    alias push push_element
+
+    def push_elements(a)
+      a.each do |e|
+        if e.kind_of? String
+          @cur_string << e
+        else
+          push_element e
+        end
+      end
+    end
+
+    def is_end?
+      @cur_string.empty? || @cur_string =~ /\s\z/
+    end
+
+    def push_string_if_present
+      unless @cur_string.empty?
+        @elements << @cur_string
+        @cur_string = ''
+      end
+    end
+
+    def push_char(c)
+      @cur_string << c
+    end
+
+    # push space into current string if
+    # there isn't one
+    def push_space
+      @cur_string << ' ' unless @cur_string[-1, 1] == ' '
+    end
+
+    def describe
+      lines = @elements.map{|x| x.inspect }.join("\n")
+      s = "Elements read in span: \n" +
+        lines.gsub(/^/, ' -') + "\n"
+
+      s += "Current string: \n  #{@cur_string.inspect}\n" unless  @cur_string.empty?
+      s
+    end
+  end
+end
diff --git a/lib/maruku/input/parse_span_better.rb b/lib/maruku/input/parse_span_better.rb
deleted file mode 100644
index 6aad788..0000000
--- a/lib/maruku/input/parse_span_better.rb
+++ /dev/null
@@ -1,746 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-require 'set'
-
-module MaRuKu; module In; module Markdown; module SpanLevelParser
-	include MaRuKu::Helpers
-	
-	EscapedCharInText = 
-		Set.new [?\\,?`,?*,?_,?{,?},?[,?],?(,?),?#,?.,?!,?|,?:,?+,?-,?>]
-
-	EscapedCharInQuotes = 
-		Set.new [?\\,?`,?*,?_,?{,?},?[,?],?(,?),?#,?.,?!,?|,?:,?+,?-,?>,?',?"]
-	
-	EscapedCharInInlineCode = [?\\,?`]
-
-	def parse_lines_as_span(lines, parent=nil)
-		parse_span_better lines.join("\n"), parent
-	end
-
-	def parse_span_better(string, parent=nil)
-		if not string.kind_of? String then 
-			error "Passed #{string.class}." end
-
-		st = (string + "")
-		st.freeze
-		src = CharSource.new(st, parent)
-		read_span(src, EscapedCharInText, [nil])
-	end
-		
-	# This is the main loop for reading span elements
-	#
-	# It's long, but not *complex* or difficult to understand.
-	#
-	#
-	def read_span(src, escaped, exit_on_chars, exit_on_strings=nil)
-		con = SpanContext.new
-		c = d = nil
-		while true
-			c = src.cur_char
-
-			# This is only an optimization which cuts 50% of the time used.
-			# (but you can't use a-zA-z in exit_on_chars)
-			if c && ((c>=?a && c<=?z) || ((c>=?A && c<=?Z)))
-				con.cur_string << src.shift_char
-				next
-			end
-
-			break if exit_on_chars && exit_on_chars.include?(c)
-			break if exit_on_strings && exit_on_strings.any? {|x| src.cur_chars_are x}
-			
-			# check if there are extensions
-			if check_span_extensions(src, con)
-				next
-			end
-			
-			case c = src.cur_char	
-			when ?\ # it's space (32)
-				if src.cur_chars_are "  \n"
-					src.ignore_chars(3)
-					con.push_element  md_br()
-					next
-				else
-					src.ignore_char
-					con.push_space 
-				end
-			when ?\n, ?\t 
-				src.ignore_char
-				con.push_space 
-			when ?`
-				read_inline_code(src,con)
-			when ?<
-				# It could be:
-				# 1) HTML "<div ..."
-				# 2) HTML "<!-- ..."
-				# 3) url "<http:// ", "<ftp:// ..."
-				# 4) email "<andrea at ... ", "<mailto:andrea at ..."
-				# 5) on itself! "a < b	"
-				# 6) Start of <<guillemettes>>
-				
-				case d = src.next_char
-					when ?<;  # guillemettes
-						src.ignore_chars(2)
-						con.push_char ?<
-						con.push_char ?<
-					when ?!; 
-						if src.cur_chars_are '<!--'
-							read_inline_html(src, con)
-						else 
-							con.push_char src.shift_char
-						end
-					when ?? 
-						read_xml_instr_span(src, con) 
-					when ?\ , ?\t 
-						con.push_char src.shift_char
-					else
-						if src.next_matches(/<mailto:/) or
-						   src.next_matches(/<[\w\.]+\@/)
-							read_email_el(src, con)
-						elsif src.next_matches(/<\w+:/)
-							read_url_el(src, con)
-						elsif src.next_matches(/<\w/)
-							#puts "This is HTML: #{src.cur_chars(20)}"
-							read_inline_html(src, con)
-						else 
-							#puts "This is NOT HTML: #{src.cur_chars(20)}"
-							con.push_char src.shift_char
-						end
-				end
-			when ?\\
-				d = src.next_char
-				if d == ?'
-					src.ignore_chars(2)
-					con.push_element md_entity('apos')
-				elsif d == ?"
-					src.ignore_chars(2)
-					con.push_element md_entity('quot')
-				elsif escaped.include? d
-					src.ignore_chars(2)
-					con.push_char d
-				else
-					con.push_char src.shift_char
-				end
-			when ?[
-				if markdown_extra? && src.next_char == ?^
-					read_footnote_ref(src,con)
-				else
-					read_link(src, con)
-				end
-			when ?!
-				if src.next_char == ?[
-					read_image(src, con)
-				else
-					con.push_char src.shift_char
-				end
-			when ?&
-				# named references
-				if m = src.read_regexp(/\&([\w\d]+);/)
-					con.push_element md_entity(m[1])
-				# numeric
-				elsif m = src.read_regexp(/\&\#(x)?([\w\d]+);/)
-					num = m[1]  ? m[2].hex : m[2].to_i
-					con.push_element md_entity(num)
-				else
-					con.push_char src.shift_char
-				end
-			when ?*
-				if not src.next_char
-					maruku_error "Opening * as last char.", src, con
-					maruku_recover "Threating as literal"
-					con.push_char src.shift_char
-				else
-					follows = src.cur_chars(4)
-					if follows =~ /^\*\*\*[^\s\*]/
-						con.push_element read_emstrong(src,'***')
-					elsif follows  =~ /^\*\*[^\s\*]/
-						con.push_element read_strong(src,'**')
-					elsif follows =~ /^\*[^\s\*]/
-						con.push_element read_em(src,'*')
-					else # * is just a normal char
-						con.push_char src.shift_char
-					end
-				end
-			when ?_
-				if not src.next_char
-					maruku_error "Opening _ as last char", src, con
-					maruku_recover "Threating as literal", src, con
-					con.push_char src.shift_char
-				else
-					# we don't want "mod_ruby" to start an emphasis
-					# so we start one only if
-					# 1) there's nothing else in the span (first char)
-					# or 2) the last char was a space
-					# or 3) the current string is empty
-					#if con.elements.empty? ||
-					if	 (con.cur_string =~ /\s\Z/) || (con.cur_string.size == 0)
-						# also, we check the next characters
-						follows = src.cur_chars(4)
-						if  follows =~ /^\_\_\_[^\s\_]/
-							con.push_element read_emstrong(src,'___')
-						elsif follows  =~ /^\_\_[^\s\_]/
-							con.push_element read_strong(src,'__')
-						elsif follows =~ /^\_[^\s\_]/
-							con.push_element read_em(src,'_')
-						else # _ is just a normal char
-							con.push_char src.shift_char
-						end
-					else
-						# _ is just a normal char
-							con.push_char src.shift_char
-					end
-				end
-			when ?{ # extension
-				if [?#, ?., ?:].include? src.next_char
-					src.ignore_char # {
-					interpret_extension(src, con, [?}])
-					src.ignore_char # }
-				else
-					con.push_char src.shift_char
-				end
-			when nil
-				maruku_error( ("Unclosed span (waiting for %s"+
-				 "#{exit_on_strings.inspect})") % [
-						exit_on_chars ? "#{exit_on_chars.inspect} or" : ""],
-						src,con)
-				break
-			else # normal text
-				con.push_char src.shift_char
-			end # end case
-		end # end while true
-		con.push_string_if_present 
-
-		# Assign IAL to elements
-		merge_ial(con.elements, src, con)
-		
-		
-		# Remove leading space
-		if (s = con.elements.first).kind_of? String
-			if s[0] == ?\ then con.elements[0] = s[1, s.size-1] end
-			con.elements.shift if s.size == 0 
-		end
-		
-		# Remove final spaces
-		if (s = con.elements.last).kind_of? String
-			s.chop! if s[-1] == ?\ 
-			con.elements.pop if s.size == 0 
-		end
-		
-		educated = educate(con.elements)
-
-		educated
-	end
-
-
-	def read_xml_instr_span(src, con) 
-		src.ignore_chars(2) # starting <?
-
-		# read target <?target code... ?>
-		target = if m = src.read_regexp(/(\w+)/)
-			m[1]
-		else
-			''
-		end
-		
-		delim = "?>"
-		
-		code = 
-			read_simple(src, escaped=[], break_on_chars=[], 
-			break_on_strings=[delim])
-		
-		src.ignore_chars delim.size
-		
-		code = (code || "").strip
-		con.push_element md_xml_instr(target, code)
-	end
-
-	# Start: cursor on character **after** '{'
-	# End: curson on '}' or EOF
-	def interpret_extension(src, con, break_on_chars)
-		case src.cur_char
-		when ?:
-			src.ignore_char # :
-			extension_meta(src, con, break_on_chars)
-		when ?#, ?.
-			extension_meta(src, con, break_on_chars)
-		else
-			stuff = read_simple(src, escaped=[?}], break_on_chars, [])
-			if stuff =~ /^(\w+\s|[^\w])/
-				extension_id = $1.strip
-				if false
-				else
-					maruku_recover "I don't know what to do with extension '#{extension_id}'\n"+
-						"I will threat this:\n\t{#{stuff}} \n as meta-data.\n", src, con
-					extension_meta(src, con, break_on_chars)
-				end
-			else 
-				maruku_recover "I will threat this:\n\t{#{stuff}} \n as meta-data.\n", src, con
-				extension_meta(src, con, break_on_chars)
-			end
-		end
-	end
-
-	def extension_meta(src, con, break_on_chars)
-		if m = src.read_regexp(/([^\s\:\"\']+):/)
-			name = m[1]
-			al = read_attribute_list(src, con, break_on_chars)
-#			puts "#{name}=#{al.inspect}"
-			self.doc.ald[name] = al
-		 	con.push md_ald(name, al)
-		else
-			al = read_attribute_list(src, con, break_on_chars)
-			self.doc.ald[name] = al
-			con.push md_ial(al)
-		end
-	end	
-
-	def read_url_el(src,con)
-		src.ignore_char # leading <
-		url = read_simple(src, [], [?>])
-		src.ignore_char # closing >
-		
-		con.push_element md_url(url)
-	end
-
-	def read_email_el(src,con)
-		src.ignore_char # leading <
-		mail = read_simple(src, [], [?>])
-		src.ignore_char # closing >
-		
-		address = mail.gsub(/^mailto:/,'')
-		con.push_element md_email(address)
-	end
-	
-	def read_url(src, break_on)
-		if [?',?"].include? src.cur_char 
-			error 'Invalid char for url', src
-		end
-		
-		url = read_simple(src, [], break_on)
-		if not url # empty url
-			url = ""
-		end
-		
-		if url[0] == ?< && url[-1] == ?>
-			url = url[1, url.size-2]
-		end
-		
-		if url.size == 0 
-			return nil
-		end
-		
-		url
-	end
-	
-	
-	def read_quoted_or_unquoted(src, con, escaped, exit_on_chars)
-		case src.cur_char
-		when ?', ?"
-			read_quoted(src, con)
-		else
-			read_simple(src, escaped, exit_on_chars)
-		end
-	end
-	
-	# Tries to read a quoted value. If stream does not
-	# start with ' or ", returns nil.
-	def read_quoted(src, con)
-		case src.cur_char
-			when ?', ?"
-				quote_char = src.shift_char # opening quote
-				string = read_simple(src, EscapedCharInQuotes, [quote_char])
-				src.ignore_char # closing quote
-				return string
-			else 
-#				puts "Asked to read quote from: #{src.cur_chars(10).inspect}"
-				return nil
-		end
-	end
-	
-	# Reads a simple string (no formatting) until one of break_on_chars, 
-	# while escaping the escaped.
-	# If the string is empty, it returns nil.
-	# Raises on error if the string terminates unexpectedly.
-#	# If eat_delim is true, and if the delim is not the EOF, then the delim
-#	# gets eaten from the stream.
-	def read_simple(src, escaped, exit_on_chars, exit_on_strings=nil)
-		text = ""
-		while true
-#			puts "Reading simple #{text.inspect}"
-			c = src.cur_char
-			if exit_on_chars && exit_on_chars.include?(c)
-#				src.ignore_char if eat_delim
-				break
-			end
-			
-			break if exit_on_strings && 
-				exit_on_strings.any? {|x| src.cur_chars_are x}
-			
-			case c
-			when nil
-				s= "String finished while reading (break on "+
-				"#{exit_on_chars.map{|x|""<<x}.inspect})"+
-				" already read: #{text.inspect}"
-				maruku_error s, src
-				maruku_recover "I boldly continue", src
-				break
-			when ?\\
-				d = src.next_char
-				if escaped.include? d
-					src.ignore_chars(2)
-					text << d
-				else
-					text << src.shift_char
-				end
-			else 
-				text << src.shift_char
-			end
-		end
-#		puts "Read simple #{text.inspect}"
-		text.empty? ? nil : text
-	end
-	
-	def read_em(src, delim)
-		src.ignore_char
-		children = read_span(src, EscapedCharInText, nil, [delim])
-		src.ignore_char
-		md_em(children)
-	end
-	
-	def read_strong(src, delim)
-		src.ignore_chars(2)
-		children = read_span(src, EscapedCharInText, nil, [delim])
-		src.ignore_chars(2)
-		md_strong(children)
-	end
-
-	def read_emstrong(src, delim)
-		src.ignore_chars(3)
-		children = read_span(src, EscapedCharInText, nil, [delim])
-		src.ignore_chars(3)
-		md_emstrong(children)
-	end
-	
-	SPACE = ?\ # = 32
-	
-#	R_REF_ID = Regexp.compile(/([^\]\s]*)(\s*\])/)
-#	R_REF_ID = Regexp.compile(/([^\]\s]*)(\s*\])/)
-	R_REF_ID = Regexp.compile(/([^\]]*)\]/)
-	
-	# Reads a bracketed id "[refid]". Consumes also both brackets.
-	def read_ref_id(src, con)
-		src.ignore_char # [
-		src.consume_whitespace
-#		puts "Next: #{src.cur_chars(10).inspect}"
-		if m = src.read_regexp(R_REF_ID) 
-#			puts "Got: #{m[1].inspect} Ignored: #{m[2].inspect}"
-#			puts "Then: #{src.cur_chars(10).inspect}"
-			m[1]
-		else
-			nil
-		end
-	end
-	
-	def read_footnote_ref(src,con)
-		ref = read_ref_id(src,con)
-		con.push_element md_foot_ref(ref)
-	end
-	
-	def read_inline_html(src, con)
-		h = HTMLHelper.new
-		begin
-			# This is our current buffer in the context
-			next_stuff = src.current_remaining_buffer
-			
-			consumed = 0
-			while true
-				if consumed >= next_stuff.size
-					maruku_error "Malformed HTML starting at #{next_stuff.inspect}", src, con
-					break
-				end
-
-				h.eat_this next_stuff[consumed].chr; consumed += 1
-				break if h.is_finished? 
-			end
-			src.ignore_chars(consumed)
-			con.push_element md_html(h.stuff_you_read)
-			
-			#start = src.current_remaining_buffer
-			# h.eat_this start
-			# if not h.is_finished?
-			# 	error "inline_html: Malformed:\n "+
-			# 		"#{start.inspect}\n #{h.inspect}",src,con
-			# end
-			# 
-			# consumed = start.size - h.rest.size 
-			# if consumed > 0
-			# 	con.push_element md_html(h.stuff_you_read)
-			# 	src.ignore_chars(consumed)
-			# else
-			# 	puts "HTML helper did not work on #{start.inspect}"
-			# 	con.push_char src.shift_char
-			# end
-		rescue Exception => e
-			maruku_error "Bad html: \n" + 
-				add_tabs(e.inspect+e.backtrace.join("\n"),1,'>'),
-				src,con
-			maruku_recover "I will try to continue after bad HTML.", src, con
-			con.push_char src.shift_char
-		end
-	end
-	
-	def read_inline_code(src, con)
-		# Count the number of ticks
-		num_ticks = 0
-		while src.cur_char == ?` 
-			num_ticks += 1
-			src.ignore_char
-		end
-		# We will read until this string
-		end_string = "`"*num_ticks
-
-		code = 
-			read_simple(src, escaped=[], break_on_chars=[], 
-				break_on_strings=[end_string])
-		
-#		puts "Now I expects #{num_ticks} ticks: #{src.cur_chars(10).inspect}"
-		src.ignore_chars num_ticks
-		
-		# Ignore at most one space
-		if num_ticks > 1 && code[0] == SPACE
-			code = code[1, code.size-1]
-		end
-		
-		# drop last space 
-		if num_ticks > 1 && code[-1] == SPACE
-			code = code[0,code.size-1]
-		end
-
-#		puts "Read `` code: #{code.inspect}; after: #{src.cur_chars(10).inspect} "
-		con.push_element md_code(code)
-	end
-	
-	def read_link(src, con)
-		# we read the string and see what happens
-		src.ignore_char # opening bracket
-		children = read_span(src, EscapedCharInText, [?]])
-		src.ignore_char # closing bracket
-
-		# ignore space
-		if src.cur_char == SPACE and 
-			(src.next_char == ?[ or src.next_char == ?( )
-			src.shift_char
-		end
-		
-		case src.cur_char
-		when ?(
-			src.ignore_char # opening (
-			src.consume_whitespace
-			url = read_url(src, [SPACE,?\t,?)])
-			if not url
-				url = '' # no url is ok
-			end
-			src.consume_whitespace
-			title = nil
-			if src.cur_char != ?) # we have a title
-				quote_char = src.cur_char
-				title = read_quoted(src,con)
-				
-				if not title
-					maruku_error 'Must quote title',src,con
-				else
-					# Tries to read a title with quotes: ![a](url "ti"tle")
-					# this is the most ugly thing in Markdown
-					if not src.next_matches(/\s*\)/)
-						# if there is not a closing par ), then read
-						# the rest and guess it's title with quotes
-						rest = read_simple(src, escaped=[], break_on_chars=[?)], 
-							break_on_strings=[])
-						# chop the closing char
-						rest.chop!
-						title << quote_char << rest
-					end
-				end
-			end
-			src.consume_whitespace
-			closing = src.shift_char # closing )
-			if closing != ?)
-				maruku_error 'Unclosed link',src,con
-				maruku_recover "No closing ): I will not create"+
-				" the link for #{children.inspect}", src, con
-				con.push_elements children
-				return
-			end
-			con.push_element md_im_link(children,url, title)
-		when ?[ # link ref
-			ref_id = read_ref_id(src,con)
-			if ref_id
-				if ref_id.size == 0
-					ref_id = sanitize_ref_id(children.to_s)
-				else
-					ref_id = sanitize_ref_id(ref_id)
-				end	
-				con.push_element md_link(children, ref_id)
-			else 
-				maruku_error "Could not read ref_id", src, con
-				maruku_recover "I will not create the link for "+
-					"#{children.inspect}", src, con
-				con.push_elements children
-				return
-			end
-		else # empty [link]
-			id = sanitize_ref_id(children.to_s) #. downcase.gsub(' ','_')
-			con.push_element md_link(children, id)
-		end
-	end # read link
-
-	def read_image(src, con)
-		src.ignore_chars(2) # opening "!["
-		alt_text = read_span(src, EscapedCharInText, [?]])
-		src.ignore_char # closing bracket
-		# ignore space
-		if src.cur_char == SPACE and 
-			(src.next_char == ?[ or src.next_char == ?( )
-			src.ignore_char
-		end
-		case src.cur_char
-		when ?(
-			src.ignore_char # opening (
-			src.consume_whitespace
-			url = read_url(src, [SPACE,?\t,?)])
-			if not url
-				error "Could not read url from #{src.cur_chars(10).inspect}",
-					src,con
-			end
-			src.consume_whitespace
-			title = nil
-			if src.cur_char != ?) # we have a title
-				quote_char = src.cur_char
-				title = read_quoted(src,con)
-				if not title
-					maruku_error 'Must quote title',src,con
-				else				
-					# Tries to read a title with quotes: ![a](url "ti"tle")
-					# this is the most ugly thing in Markdown
-					if not src.next_matches(/\s*\)/)
-						# if there is not a closing par ), then read
-						# the rest and guess it's title with quotes
-						rest = read_simple(src, escaped=[], break_on_chars=[?)], 
-							break_on_strings=[])
-						# chop the closing char
-						rest.chop!
-						title << quote_char << rest
-					end
-				end
-			end
-			src.consume_whitespace
-			closing = src.shift_char # closing )
-			if closing != ?)
-				error( ("Unclosed link: '"<<closing<<"'")+
-					" Read url=#{url.inspect} title=#{title.inspect}",src,con)
-			end
-			con.push_element md_im_image(alt_text, url, title)
-		when ?[ # link ref
-			ref_id = read_ref_id(src,con)
-			if not ref_id # TODO: check around
-				error('Reference not closed.', src, con)
-				ref_id = ""
-			end
-			if ref_id.size == 0
-				ref_id =  alt_text.to_s
-			end
-
-			ref_id = sanitize_ref_id(ref_id)
-
-			con.push_element md_image(alt_text, ref_id)
-		else # no stuff
-			ref_id =  sanitize_ref_id(alt_text.to_s)
-			con.push_element md_image(alt_text, ref_id)
-		end
-	end # read link
-
-
-	class SpanContext 
-		include MaRuKu::Strings
-	
-		# Read elements
-		attr_accessor :elements
-		attr_accessor :cur_string
-	
-		def initialize
-			@elements = []
-			@cur_string = ""
-		end
-	
-		def push_element(e)
-			raise "Only MDElement and String, please. You pushed #{e.class}: #{e.inspect} " if
-			 not (e.kind_of?(String) or e.kind_of?(MDElement))
-		
-			push_string_if_present
-			@elements << e
-			nil
-		end
-		alias push push_element
-		
-		def push_elements(a)
-			for e in a 
-				if e.kind_of? String
-					e.each_byte do |b| push_char b end
-				else
-					push_element e
-				end
-			end
-		end
-		
-		def push_string_if_present
-			if @cur_string.size > 0
-				@elements << @cur_string
-				@cur_string = ""
-			end
-			nil
-		end
-	
-		def push_char(c)
-			@cur_string << c 
-			nil
-		end
-	
-		# push space into current string if
-		# there isn't one
-		def push_space
-			last = @cur_string[@cur_string.size-1]
-			@cur_string << ?\  if last != ?\ 
-		end
-	
-		def describe
-			lines = @elements.map{|x| x.inspect}.join("\n")
-			s = "Elements read in span: \n" +
-			add_tabs(lines,1, ' -')+"\n"
-		
-			if @cur_string.size > 0
-			s += "Current string: \n  #{@cur_string.inspect}\n" 
-			end
-			s
-		end
-	end # SpanContext
-	
-end end end end # module MaRuKu; module In; module Markdown; module SpanLevelParser
-
diff --git a/lib/maruku/input/rubypants.rb b/lib/maruku/input/rubypants.rb
index 02b52ab..6bb06c5 100644
--- a/lib/maruku/input/rubypants.rb
+++ b/lib/maruku/input/rubypants.rb
@@ -1,33 +1,13 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-#
-# NOTA BENE: 
-#
-# The following algorithm is a rip-off of RubyPants written by 
-# Christian Neukirchen. 
+#
+# NOTA BENE:
+#
+# The following algorithm is a rip-off of RubyPants written by
+# Christian Neukirchen.
 #
 # RubyPants is a Ruby port of SmartyPants written by John Gruber.
 #
-# This file is distributed under the GPL, which I guess is compatible
-# with the terms of the RubyPants license.
+# This file is distributed under the MIT license, which is compatible
+# with the terms of the RubyPants license (3-clause BSD).
 #
 # -- Andrea Censi
 
@@ -51,39 +31,39 @@
 # [snip]
 #
 # == Authors
-# 
+#
 # John Gruber did all of the hard work of writing this software in
 # Perl for Movable Type and almost all of this useful documentation.
 # Chad Miller ported it to Python to use with Pyblosxom.
 #
 # Christian Neukirchen provided the Ruby port, as a general-purpose
 # library that follows the *Cloth API.
-# 
+#
 #
 # == Copyright and License
-# 
+#
 # === SmartyPants license:
-# 
+#
 # Copyright (c) 2003 John Gruber
 # (http://daringfireball.net)
 # 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 "SmartyPants" 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
@@ -96,23 +76,23 @@
 # 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.
-# 
+#
 # === RubyPants license
-# 
+#
 # RubyPants is a derivative work of SmartyPants and smartypants.py.
-# 
+#
 # 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.
-# 
+#
 # 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
@@ -125,7 +105,7 @@
 # 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.
-# 
+#
 #
 # == Links
 #
@@ -137,89 +117,194 @@
 # Christian Neukirchen:: http://kronavita.de/chris
 
 
-module MaRuKu; module In; module Markdown; module SpanLevelParser
-	Punct_class = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
-	Close_class = %![^\ \t\r\n\\[\{\(\-]!
-
-	Rules = [
-		[/---/,   :mdash          ],
-		[/--/,    :ndash          ],
-		['...',   :hellip         ],
-		['. . .', :hellip         ],
-		["``",    :ldquo          ],
-		["''",    :rdquo          ],
-		[/<<\s/,  [:laquo, :nbsp] ],
-		[/\s>>/,  [:nbsp, :raquo] ],
-		[/<</,    :laquo          ],
-		[/>>/,    :raquo          ],
-		
-#		def educate_single_backticks(str)
-#		["`", :lsquo]
-#		["'", :rsquo]
-
-		# Special case if the very first character is a quote followed by
-		# punctuation at a non-word-break. Close the quotes by brute
-		# force:
-		[/^'(?=#{Punct_class}\B)/, :rsquo],
-		[/^"(?=#{Punct_class}\B)/, :rdquo],
-		# Special case for double sets of quotes, e.g.:
-		#   <p>He said, "'Quoted' words in a larger quote."</p>
-		[/"'(?=\w)/, [:ldquo, :lsquo]    ],
-		[/'"(?=\w)/, [:lsquo, :ldquo]    ],
-		# Special case for decade abbreviations (the '80s):
-		[/'(?=\d\ds)/, :rsquo            ],
-		# Get most opening single quotes:
-		[/(\s)'(?=\w)/, [:one, :lsquo]   ],
-		# Single closing quotes:
-		[/(#{Close_class})'/, [:one, :rsquo]],
-		[/'(\s|s\b|$)/, [:rsquo, :one]],
-		# Any remaining single quotes should be opening ones:
-		[/'/, :lsquo],
-		# Get most opening double quotes:
-		[/(\s)"(?=\w)/, [:one, :ldquo]],
-		# Double closing quotes:
-		[/(#{Close_class})"/, [:one, :rdquo]],
-		[/"(\s|s\b|$)/, [:rdquo, :one]],
-		# Any remaining quotes should be opening ones:
-		[/"/, :ldquo]
-	].
-	map{|reg, subst| # People should do the thinking, machines should do the work.
-		reg = Regexp.new(Regexp.escape(reg)) if not reg.kind_of? Regexp
-		subst = [subst] if not subst.kind_of?Array
-		[reg, subst]}
-
-# note: input will be destroyed
-def apply_one_rule(reg, subst, input)
-	output = []
-	while first = input.shift
-		if first.kind_of?(String) && (m = reg.match(first))
-			output.push    m. pre_match if m. pre_match.size > 0
-			 input.unshift m.post_match if m.post_match.size > 0
-			subst.reverse.each do |x|
-				input.unshift( x == :one ? m[1] : md_entity(x.to_s) ) end
-		else
-			output.push first
-		end
-	end
-	return output
-end
-	
-def educate(elements)
-	Rules.each do |reg, subst|
-		elements = apply_one_rule(reg, subst, elements)
-	end
-	# strips empty strings
-	elements.delete_if {|x| x.kind_of?(String) && x.size == 0}
-	final = []
-	# join consecutive strings
-	elements.each do |x|
-		if x.kind_of?(String) && final.last.kind_of?(String)
-			final.last << x
-		else
-			final << x
-		end
-	end
-	return final
-end
+module MaRuKu::In::Markdown::SpanLevelParser
+  Punct_class = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
+  Close_class = "[^\ \t\r\n\\[\{\(\-]"
+
+  # A rule to apply a particular pattern (like double quotes)
+  # against a list of strings and MDElements, replacing that
+  # pattern with the smartypants version.
+  class Rule
+    # The pattern to search for
+    attr_accessor :pattern
+
+    # The replacement tokens (entities or other instructions)
+    attr_accessor :replacement
+
+    # This is a hack to allow us to build entities.
+    attr_accessor :doc
+
+    def initialize(pattern, replacement)
+      @pattern = pattern
+      @replacement = replacement
+    end
+
+    private
+
+    # Add something to the output array. If it's
+    # not a string (like an MDElement) just add it direcltly,
+    # otherwise attempt to add on to the last element in the
+    # output if it's a string.
+    def append_to_output(output, str)
+      if !str.kind_of?(String)
+        output << str
+        return
+      end
+      return if str.empty?
+      if output.last.kind_of?(String)
+        output.last << str
+      else
+        output << str
+      end
+    end
+  end
+
+  # Simple rule that says "Replace this pattern with these entities"
+  class ReplaceRule < Rule
+    # Replace all matches in the input at once with the
+    # same elements from "replacement".
+    def apply(first, input, output)
+      split = first.split(pattern)
+      if split.empty?
+        first.scan(pattern).size.times do
+          clone_elems(replacement).each do |x|
+            append_to_output(output, x)
+          end
+        end
+      else
+        intersperse(first.split(pattern), replacement).each do |x|
+          append_to_output(output, x)
+        end
+      end
+    end
 
-end end end end
+    private
+
+    # Sort of like "join" - places the elements in "elem"
+    # between each adjacent element in the array.
+    def intersperse(ary, elem)
+      return clone_elems(elem) if ary.empty?
+      return ary if ary.length == 1
+      h, *t = ary
+      t.inject([h]) do |r, e|
+        r.concat clone_elems(elem)
+        r << e
+      end
+    end
+
+    def clone_elems(elems)
+      elems.map do |el|
+        en = el.clone
+        en.doc = doc
+        en
+      end
+    end
+  end
+
+  # A more complex rule that uses a capture group from the
+  # pattern in its replacement.
+  class CaptureRule < Rule
+    # One at a time, replace each match, including
+    # some part of the match, and put the rest back into
+    # input to be processed next.
+    def apply(first, input, output)
+      if pattern =~ first
+        m = Regexp.last_match
+        append_to_output(output, m.pre_match)
+        input.unshift m.post_match unless m.post_match.empty?
+        replacement.reverse_each do |sub|
+          if sub == :one
+            input.unshift m[1]
+          else
+            entity = sub.clone
+            sub.doc = doc
+            input.unshift entity
+          end
+        end
+      else
+        append_to_output(output, first)
+      end
+    end
+  end
+
+  # All the rules that will be applied (in order) to smarten the document.
+  Rules =
+    [
+     ['---',   :mdash          ],
+     ['--',    :ndash          ],
+     ['...',   :hellip         ],
+     ['. . .', :hellip         ],
+     ["``",    :ldquo          ],
+     ["''",    :rdquo          ],
+     [/<<\s/,  [:laquo, :nbsp] ],
+     [/\s>>/,  [:nbsp, :raquo] ],
+     ['<<',    :laquo          ],
+     ['>>',    :raquo          ],
+
+     # Special case if the very first character is a quote followed by
+     # punctuation at a non-word-break. Close the quotes by brute
+     # force:
+     [/\A'(?=#{Punct_class}\B)/, :rsquo],
+     [/\A"(?=#{Punct_class}\B)/, :rdquo],
+     # Special case for double sets of quotes, e.g.:
+     #   <p>He said, "'Quoted' words in a larger quote."</p>
+     [/"'(?=\w)/, [:ldquo, :lsquo]    ],
+     [/'"(?=\w)/, [:lsquo, :ldquo]    ],
+     # Special case for decade abbreviations (the '80s):
+     [/'(?=\d\ds)/, :rsquo            ],
+     # Get most opening single quotes:
+     [/(\s)'(?=\w)/, [:one, :lsquo]   ],
+     # Single closing quotes:
+     [/(#{Close_class})'/, [:one, :rsquo]],
+     [/'(\s|s\b|$)/, [:rsquo, :one]],
+     # Any remaining single quotes should be opening ones:
+     ["'", :lsquo],
+     # Get most opening double quotes:
+     [/(\s)"(?=\w)/, [:one, :ldquo]],
+     # Double closing quotes:
+     [/(#{Close_class})"/, [:one, :rdquo]],
+     [/"(\s|s\b|$)/, [:rdquo, :one]],
+     # Any remaining quotes should be opening ones:
+     ['"', :ldquo]
+    ].
+  map do |reg, subst| # People should do the thinking, machines should do the work.
+    captures = false
+    subst = Array(subst).map do |s|
+      if s == :one
+        captures = true
+        s
+      else
+        MaRuKu::MDElement.new(:entity, [], { :entity_name => s.to_s.freeze }, nil)
+      end
+    end.freeze
+
+    if captures
+      CaptureRule.new reg, subst
+    else
+      ReplaceRule.new reg, subst
+    end
+  end
+
+  # Fully apply a single rule to an entire array
+  # of elements.
+  # note: input will be modified in place
+  def apply_one_rule!(rule, input)
+    output = []
+    while first = input.shift
+      if first.kind_of?(String)
+        rule.doc = @doc
+        rule.apply(first, input, output)
+      else
+        output << first
+      end
+    end
+    output
+  end
+
+  # Transform elements to have SmartyPants punctuation.
+  def educate(elements)
+    Rules.inject(elements) do |elems, rule|
+      apply_one_rule!(rule, elems)
+    end
+  end
+end
diff --git a/lib/maruku/input/type_detection.rb b/lib/maruku/input/type_detection.rb
deleted file mode 100644
index e019414..0000000
--- a/lib/maruku/input/type_detection.rb
+++ /dev/null
@@ -1,147 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-class String
-	include MaRuKu::Strings
-	def md_type()
-		@md_type ||= line_md_type(self)
-	end
-end
-
-class NilClass
-	def md_type() nil end
-	
-end
-
-# This code does the classification of lines for block-level parsing.
-module MaRuKu; module Strings
-	
-	def line_md_type(l)
-		# The order of evaluation is important (:text is a catch-all)
-		return :text   if l =~ /^[a-zA-Z]/
-		return :code             if number_of_leading_spaces(l)>=4
-		return :empty    if l =~ /^\s*$/
-		return :footnote_text    if l =~ FootnoteText
-		return :ref_definition   if l =~ LinkRegex or l=~ IncompleteLink
-		return :abbreviation     if l =~ Abbreviation
-		return :definition       if l =~ Definition
-		# I had a bug with emails and urls at the beginning of the 
-		# line that were mistaken for raw_html
-		return :text if l=~ /^[ ]{0,3}#{EMailAddress}/
-		return :text if l=~ /^[ ]{0,3}<http:/
-		# raw html is like PHP Markdown Extra: at most three spaces before
-		return :xml_instr if l =~ %r{^\s*<\?}
-		return :raw_html if l =~ %r{^[ ]?[ ]?[ ]?</?\s*\w+}
-		return :raw_html if l =~ %r{^[ ]?[ ]?[ ]?<\!\-\-}
-		# Something is wrong with how we parse lists! :-(
-		#return :ulist    if l =~ /^[ ]{0,3}([\*\-\+])\s+.*\w+/
-		#return :olist    if l =~ /^[ ]{0,3}\d+\..*\w+/
-		return :ulist    if l =~ /^[ ]{0,1}([\*\-\+])\s+.*\w+/
-		return :olist    if l =~ /^[ ]{0,1}\d+\..*\w+/
-		return :header1  if l =~ /^(=)+/ 
-		return :header2  if l =~ /^([-\s])+$/ 
-		return :header3  if l =~ /^(#)+\s*\S+/ 
-		# at least three asterisks on a line, and only whitespace
-		return :hrule    if l =~ /^(\s*\*\s*){3,1000}$/ 
-		return :hrule    if l =~ /^(\s*-\s*){3,1000}$/ # or hyphens
-		return :hrule    if l =~ /^(\s*_\s*){3,1000}$/ # or underscores	
-		return :quote    if l =~ /^>/
-		return :metadata if l =~ /^@/
-#		if @@new_meta_data?
-			return :ald   if l =~ AttributeDefinitionList
-			return :ial   if l =~ InlineAttributeList
-#		end
-#		return :equation_end if l =~ EquationEnd
-		return :text # else, it's just text
-	end
-
-		
-	# $1 = id   $2 = attribute list
-	AttributeDefinitionList = /^\s{0,3}\{([\w\d\s]+)\}:\s*(.*)\s*$/
-	# 
-	InlineAttributeList = /^\s{0,3}\{([:#\.].*)\}\s*$/
-	# Example:
-	#     ^:blah blah
-	#     ^: blah blah
-	#     ^   : blah blah
-	Definition = %r{ 
-		^ # begin of line
-		[ ]{0,3} # up to 3 spaces
-		: # colon
-		\s* # whitespace
-		(\S.*) # the text    = $1
-		$ # end of line
-	}x
-
-	# Example:
-	#     *[HTML]: Hyper Text Markup Language
-	Abbreviation = %r{
-		^  # begin of line
-		[ ]{0,3} # up to 3 spaces
-		\* # one asterisk
-		\[ # opening bracket
-		([^\]]+) # any non-closing bracket:  id = $1
-		\] # closing bracket
-		:  # colon
-		\s* # whitespace
-		(\S.*\S)* #           definition=$2
-		\s* # strip this whitespace
-		$   # end of line
-	}x
-
-	FootnoteText = %r{
-		^  # begin of line
-		[ ]{0,3} # up to 3 spaces
-		\[(\^.+)\]: # id = $1 (including '^')
-		\s*(\S.*)?$    # text = $2 (not obb.)
-	}x
-
-	# This regex is taken from BlueCloth sources
-	# Link defs are in the form: ^[id]: \n? url "optional title"
-	LinkRegex = %r{
-		^[ ]{0,3}\[([^\[\]]+)\]:		# id = $1
-		  [ ]*
-		<?([^>\s]+)>?				# url = $2
-		  [ ]*
-		(?:# Titles are delimited by "quotes" or (parens).
-			["(']
-			(.+?)			# title = $3
-			[")']			# Matching ) or "
-			\s*(.+)?   # stuff = $4
-		)?	# title is optional
-	  }x
-
-	IncompleteLink = %r{^[ ]{0,3}\[([^\[\]]+)\]:\s*$}
-
-	HeaderWithId = /^(.*)\{\#([\w_-]+)\}\s*$/
-
-	HeaderWithAttributes = /^(.*)\{(.*)\}\s*$/
-
-
-	# if contains a pipe, it could be a table header
-	MightBeTableHeader = %r{\|}
-	# -------------:
-	Sep = /\s*(\:)?\s*-+\s*(\:)?\s*/
-	# | -------------:| ------------------------------ |
-	TableSeparator = %r{^(\|?#{Sep}\|?)+\s*$}
-
-
-	EMailAddress = /<([^:]+@[^:]+)>/
-end end
diff --git a/lib/maruku/inspect_element.rb b/lib/maruku/inspect_element.rb
new file mode 100644
index 0000000..aafc056
--- /dev/null
+++ b/lib/maruku/inspect_element.rb
@@ -0,0 +1,60 @@
+module MaRuKu
+  class MDElement
+    INSPECT_FORMS = {
+      :paragraph          => ["par",      :children],
+      :footnote_reference => ["foot_ref", :footnote_id],
+      :entity             => ["entity",   :entity_name],
+      :email_address      => ["email",    :email],
+      :inline_code        => ["code",     :raw_code],
+      :raw_html           => ["html",     :raw_html],
+      :emphasis           => ["em",       :children],
+      :strong             => ["strong",   :children],
+      :immediate_link     => ["url",      :url],
+      :image              => ["image",    :children, :ref_id],
+      :im_image           => ["im_image", :children, :url, :title],
+      :link               => ["link",     :children, :ref_id],
+      :im_link            => ["im_link",  :children, :url, :title],
+      :ref_definition     => ["ref_def",  :ref_id, :url, :title],
+      :ial                => ["ial",      :ial],
+      :li                 => ["li",       :children, :want_my_paragraph]
+    }
+
+    # Outputs the document AST as calls to document helpers.
+    # (this should be `eval`-able to get a copy of the original element).
+    def inspect
+      if INSPECT_FORMS.has_key? @node_type
+        name, *params = INSPECT_FORMS[@node_type]
+
+        params = params.map do |p|
+          if p == :children
+            children_inspect
+          else
+            send(p).inspect
+          end
+        end
+        params << @al.inspect if @al && !@al.empty?
+      else
+        name = 'el'
+        params = [self.node_type.inspect, children_inspect]
+        params << @meta_priv.inspect unless @meta_priv.empty? && self.al.empty?
+        params << self.al.inspect unless self.al.empty?
+      end
+
+      "md_#{name}(#{params.join(', ')})"
+    end
+
+    private
+
+    def children_inspect
+      kids = @children.map(&:inspect)
+      return kids.first if kids.size == 1
+
+      comma = kids.join(", ")
+      if comma.size < 70
+        "[#{comma}]"
+      else
+        "[\n\t#{kids.join(",\n\t")}\n]"
+      end
+    end
+  end
+end
diff --git a/lib/maruku/maruku.rb b/lib/maruku/maruku.rb
index 6be6bfa..41998dc 100644
--- a/lib/maruku/maruku.rb
+++ b/lib/maruku/maruku.rb
@@ -1,33 +1,17 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
+# The public interface for Maruku.
 #
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
+# @example Render a document fragment
+# Maruku.new("## Header ##").to_html
+# # => "<h2 id='header'>header</h2>"
+class Maruku < MaRuKu::MDDocument
+  def initialize(s = nil, meta = {})
+    super()
+    self.attributes.merge! meta
+    parse_doc(s) if s
+  end
 
-
-# The Maruku class is the public interface
-#
-
-class Maruku
-	def initialize(s=nil, meta={})
-		super(nil)
-		self.attributes.merge! meta
-		if s
-			parse_doc(s)
-		end
-	end
+  def to_s
+    warn "Maruku#to_s is deprecated and will be removed or changed in a near-future version of Maruku."
+    super
+  end
 end
diff --git a/lib/maruku/output/entity_table.rb b/lib/maruku/output/entity_table.rb
new file mode 100644
index 0000000..98edc06
--- /dev/null
+++ b/lib/maruku/output/entity_table.rb
@@ -0,0 +1,33 @@
+require 'rexml/document'
+require 'singleton'
+
+module MaRuKu::Out
+  Entity = Struct.new(:html_num, :html_entity, :latex_string, :latex_package)
+
+  class EntityTable
+    # Sad but true
+    include Singleton
+
+    def initialize
+      @entity_table = {}
+
+      xml = File.new(File.join(File.dirname(__FILE__), '..', '..', '..', 'data', 'entities.xml'))
+      doc = REXML::Document.new(xml)
+      doc.elements.each("//char") do |c|
+        num = c.attributes['num'].to_i
+        name = c.attributes['name']
+        convert = c.attributes['convertTo']
+        package = c.attributes['package']
+
+        e = Entity.new(num, name, convert, package)
+        @entity_table[name] = e
+        @entity_table[num] = e
+      end
+    end
+
+    def entity(name)
+      @entity_table[name]
+    end
+  end
+end
+
diff --git a/lib/maruku/output/s5/fancy.rb b/lib/maruku/output/s5/fancy.rb
index 977bb53..8b1d343 100644
--- a/lib/maruku/output/s5/fancy.rb
+++ b/lib/maruku/output/s5/fancy.rb
@@ -1,17 +1,17 @@
 module MaRuKu
-	S5_external =<<EOF
-	
-	<meta name="defaultView" content="slideshow" />
-	<meta name="controlVis" content="hidden" />
-	<link rel="stylesheet" href="ui/default/slides.css" type="text/css" media="projection" id="slideProj" />
-	<link rel="stylesheet" href="ui/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
-	<link rel="stylesheet" href="ui/default/print.css" type="text/css" media="print" id="slidePrint" />
-	<link rel="stylesheet" href="ui/default/opera.css" type="text/css" media="projection" id="operaFix" />
-	<script src="ui/default/slides.js" type="text/javascript"> </script>
+  S5_external =<<EOF
+
+  <meta name="defaultView" content="slideshow" />
+  <meta name="controlVis" content="hidden" />
+  <link rel="stylesheet" href="ui/default/slides.css" type="text/css" media="projection" id="slideProj" />
+  <link rel="stylesheet" href="ui/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
+  <link rel="stylesheet" href="ui/default/print.css" type="text/css" media="print" id="slidePrint" />
+  <link rel="stylesheet" href="ui/default/opera.css" type="text/css" media="projection" id="operaFix" />
+  <script src="ui/default/slides.js" type="text/javascript"> </script>
 EOF
 
 
-	S5_Fancy =<<EOF
+  S5_Fancy =<<EOF
 
 <meta name="defaultView" content="slideshow" />
 <meta name="controlVis" content="hidden" />
@@ -20,7 +20,7 @@ EOF
 /* Do not edit or override these styles! The system will likely break if you do. */
 
 div#header, div#footer, div#controls, .slide {position: absolute;}
-html>body div#header, html>body div#footer, 
+html>body div#header, html>body div#footer,
   html>body div#controls, html>body .slide {position: fixed;}
 .handout {display: none;}
 .layout {display: block;}
@@ -29,7 +29,7 @@ html>body div#header, html>body div#footer,
 
 /* The following styles size, place, and layer the slide components.
    Edit these if you want to change the overall slide layout.
-   The commented lines can be uncommented (and modified, if necessary) 
+   The commented lines can be uncommented (and modified, if necessary)
     to help you with the rearrangement process. */
 
 /* target = 1024x768 */
@@ -105,8 +105,8 @@ html>body div#controls {position: fixed; padding: 0 0 1em 0;
   top: auto;}
 div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
   margin: 0; padding: 0;}
-#controls #navLinks a {padding: 0; margin: 0 0.5em; 
-  background: #005; border: none; color: #779; 
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+  background: #005; border: none; color: #779;
   cursor: pointer;}
 #controls #navList {height: 1em;}
 #controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #DDD; color: #227;}
@@ -141,9 +141,9 @@ li:after {content: " [" attr(class) "]"; color: #F88;}
 <style type="text/css" media="projection" id="operaFix">
 /* DO NOT CHANGE THESE unless you really want to break Opera Show */
 .slide {
-	visibility: visible !important;
-	position: static !important;
-	page-break-before: always;
+  visibility: visible !important;
+  position: static !important;
+  page-break-before: always;
 }
 #slide0 {page-break-before: avoid;}
 
@@ -197,7 +197,7 @@ p.example {display: none;}
 <![CDATA[
 // S5 v1.1 slides.js -- released into the Public Domain
 //
-// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information 
+// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information
 // about all the wonderful and talented contributors to this code!
 
 var undef;
@@ -215,535 +215,535 @@ var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0;
 var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0;
 
 function hasClass(object, className) {
-	if (!object.className) return false;
-	return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1);
+  if (!object.className) return false;
+  return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1);
 }
 
 function hasValue(object, value) {
-	if (!object) return false;
-	return (object.search('(^|\\s)' + value + '(\\s|$)') != -1);
+  if (!object) return false;
+  return (object.search('(^|\\s)' + value + '(\\s|$)') != -1);
 }
 
 function removeClass(object,className) {
-	if (!object) return;
-	object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2);
+  if (!object) return;
+  object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2);
 }
 
 function addClass(object,className) {
-	if (!object || hasClass(object, className)) return;
-	if (object.className) {
-		object.className += ' '+className;
-	} else {
-		object.className = className;
-	}
+  if (!object || hasClass(object, className)) return;
+  if (object.className) {
+    object.className += ' '+className;
+  } else {
+    object.className = className;
+  }
 }
 
 function GetElementsWithClassName(elementName,className) {
-	var allElements = document.getElementsByTagName(elementName);
-	var elemColl = new Array();
-	for (var i = 0; i< allElements.length; i++) {
-		if (hasClass(allElements[i], className)) {
-			elemColl[elemColl.length] = allElements[i];
-		}
-	}
-	return elemColl;
+  var allElements = document.getElementsByTagName(elementName);
+  var elemColl = new Array();
+  for (var i = 0; i< allElements.length; i++) {
+    if (hasClass(allElements[i], className)) {
+      elemColl[elemColl.length] = allElements[i];
+    }
+  }
+  return elemColl;
 }
 
 function isParentOrSelf(element, id) {
-	if (element == null || element.nodeName=='BODY') return false;
-	else if (element.id == id) return true;
-	else return isParentOrSelf(element.parentNode, id);
+  if (element == null || element.nodeName=='BODY') return false;
+  else if (element.id == id) return true;
+  else return isParentOrSelf(element.parentNode, id);
 }
 
 function nodeValue(node) {
-	var result = "";
-	if (node.nodeType == 1) {
-		var children = node.childNodes;
-		for (var i = 0; i < children.length; ++i) {
-			result += nodeValue(children[i]);
-		}		
-	}
-	else if (node.nodeType == 3) {
-		result = node.nodeValue;
-	}
-	return(result);
+  var result = "";
+  if (node.nodeType == 1) {
+    var children = node.childNodes;
+    for (var i = 0; i < children.length; ++i) {
+      result += nodeValue(children[i]);
+    }
+  }
+  else if (node.nodeType == 3) {
+    result = node.nodeValue;
+  }
+  return(result);
 }
 
 function slideLabel() {
-	var slideColl = GetElementsWithClassName('*','slide');
-	var list = document.getElementById('jumplist');
-	smax = slideColl.length;
-	for (var n = 0; n < smax; n++) {
-		var obj = slideColl[n];
-
-		var did = 'slide' + n.toString();
-		obj.setAttribute('id',did);
-		if (isOp) continue;
-
-		var otext = '';
-		var menu = obj.firstChild;
-		if (!menu) continue; // to cope with empty slides
-		while (menu && menu.nodeType == 3) {
-			menu = menu.nextSibling;
-		}
-	 	if (!menu) continue; // to cope with slides with only text nodes
-
-		var menunodes = menu.childNodes;
-		for (var o = 0; o < menunodes.length; o++) {
-			otext += nodeValue(menunodes[o]);
-		}
-		list.options[list.length] = new Option(n + ' : '  + otext, n);
-	}
+  var slideColl = GetElementsWithClassName('*','slide');
+  var list = document.getElementById('jumplist');
+  smax = slideColl.length;
+  for (var n = 0; n < smax; n++) {
+    var obj = slideColl[n];
+
+    var did = 'slide' + n.toString();
+    obj.setAttribute('id',did);
+    if (isOp) continue;
+
+    var otext = '';
+    var menu = obj.firstChild;
+    if (!menu) continue; // to cope with empty slides
+    while (menu && menu.nodeType == 3) {
+      menu = menu.nextSibling;
+    }
+    if (!menu) continue; // to cope with slides with only text nodes
+
+    var menunodes = menu.childNodes;
+    for (var o = 0; o < menunodes.length; o++) {
+      otext += nodeValue(menunodes[o]);
+    }
+    list.options[list.length] = new Option(n + ' : '  + otext, n);
+  }
 }
 
 function currentSlide() {
-	var cs;
-	if (document.getElementById) {
-		cs = document.getElementById('currentSlide');
-	} else {
-		cs = document.currentSlide;
-	}
-	cs.innerHTML = '<span id="csHere">' + snum + '<\/span> ' + 
-		'<span id="csSep">\/<\/span> ' + 
-		'<span id="csTotal">' + (smax-1) + '<\/span>';
-	if (snum == 0) {
-		cs.style.visibility = 'hidden';
-	} else {
-		cs.style.visibility = 'visible';
-	}
+  var cs;
+  if (document.getElementById) {
+    cs = document.getElementById('currentSlide');
+  } else {
+    cs = document.currentSlide;
+  }
+  cs.innerHTML = '<span id="csHere">' + snum + '<\/span> ' +
+    '<span id="csSep">\/<\/span> ' +
+    '<span id="csTotal">' + (smax-1) + '<\/span>';
+  if (snum == 0) {
+    cs.style.visibility = 'hidden';
+  } else {
+    cs.style.visibility = 'visible';
+  }
 }
 
 function go(step) {
-	if (document.getElementById('slideProj').disabled || step == 0) return;
-	var jl = document.getElementById('jumplist');
-	var cid = 'slide' + snum;
-	var ce = document.getElementById(cid);
-	if (incrementals[snum].length > 0) {
-		for (var i = 0; i < incrementals[snum].length; i++) {
-			removeClass(incrementals[snum][i], 'current');
-			removeClass(incrementals[snum][i], 'incremental');
-		}
-	}
-	if (step != 'j') {
-		snum += step;
-		lmax = smax - 1;
-		if (snum > lmax) snum = lmax;
-		if (snum < 0) snum = 0;
-	} else
-		snum = parseInt(jl.value);
-	var nid = 'slide' + snum;
-	var ne = document.getElementById(nid);
-	if (!ne) {
-		ne = document.getElementById('slide0');
-		snum = 0;
-	}
-	if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;}
-	if (incrementals[snum].length > 0 && incpos == 0) {
-		for (var i = 0; i < incrementals[snum].length; i++) {
-			if (hasClass(incrementals[snum][i], 'current'))
-				incpos = i + 1;
-			else
-				addClass(incrementals[snum][i], 'incremental');
-		}
-	}
-	if (incrementals[snum].length > 0 && incpos > 0)
-		addClass(incrementals[snum][incpos - 1], 'current');
-	ce.style.visibility = 'hidden';
-	ne.style.visibility = 'visible';
-	jl.selectedIndex = snum;
-	currentSlide();
-	number = 0;
+  if (document.getElementById('slideProj').disabled || step == 0) return;
+  var jl = document.getElementById('jumplist');
+  var cid = 'slide' + snum;
+  var ce = document.getElementById(cid);
+  if (incrementals[snum].length > 0) {
+    for (var i = 0; i < incrementals[snum].length; i++) {
+      removeClass(incrementals[snum][i], 'current');
+      removeClass(incrementals[snum][i], 'incremental');
+    }
+  }
+  if (step != 'j') {
+    snum += step;
+    lmax = smax - 1;
+    if (snum > lmax) snum = lmax;
+    if (snum < 0) snum = 0;
+  } else
+    snum = parseInt(jl.value);
+  var nid = 'slide' + snum;
+  var ne = document.getElementById(nid);
+  if (!ne) {
+    ne = document.getElementById('slide0');
+    snum = 0;
+  }
+  if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;}
+  if (incrementals[snum].length > 0 && incpos == 0) {
+    for (var i = 0; i < incrementals[snum].length; i++) {
+      if (hasClass(incrementals[snum][i], 'current'))
+        incpos = i + 1;
+      else
+        addClass(incrementals[snum][i], 'incremental');
+    }
+  }
+  if (incrementals[snum].length > 0 && incpos > 0)
+    addClass(incrementals[snum][incpos - 1], 'current');
+  ce.style.visibility = 'hidden';
+  ne.style.visibility = 'visible';
+  jl.selectedIndex = snum;
+  currentSlide();
+  number = 0;
 }
 
 function goTo(target) {
-	if (target >= smax || target == snum) return;
-	go(target - snum);
+  if (target >= smax || target == snum) return;
+  go(target - snum);
 }
 
 function subgo(step) {
-	if (step > 0) {
-		removeClass(incrementals[snum][incpos - 1],'current');
-		removeClass(incrementals[snum][incpos], 'incremental');
-		addClass(incrementals[snum][incpos],'current');
-		incpos++;
-	} else {
-		incpos--;
-		removeClass(incrementals[snum][incpos],'current');
-		addClass(incrementals[snum][incpos], 'incremental');
-		addClass(incrementals[snum][incpos - 1],'current');
-	}
+  if (step > 0) {
+    removeClass(incrementals[snum][incpos - 1],'current');
+    removeClass(incrementals[snum][incpos], 'incremental');
+    addClass(incrementals[snum][incpos],'current');
+    incpos++;
+  } else {
+    incpos--;
+    removeClass(incrementals[snum][incpos],'current');
+    addClass(incrementals[snum][incpos], 'incremental');
+    addClass(incrementals[snum][incpos - 1],'current');
+  }
 }
 
 function toggle() {
-	var slideColl = GetElementsWithClassName('*','slide');
-	var slides = document.getElementById('slideProj');
-	var outline = document.getElementById('outlineStyle');
-	if (!slides.disabled) {
-		slides.disabled = true;
-		outline.disabled = false;
-		s5mode = false;
-		fontSize('1em');
-		for (var n = 0; n < smax; n++) {
-			var slide = slideColl[n];
-			slide.style.visibility = 'visible';
-		}
-	} else {
-		slides.disabled = false;
-		outline.disabled = true;
-		s5mode = true;
-		fontScale();
-		for (var n = 0; n < smax; n++) {
-			var slide = slideColl[n];
-			slide.style.visibility = 'hidden';
-		}
-		slideColl[snum].style.visibility = 'visible';
-	}
+  var slideColl = GetElementsWithClassName('*','slide');
+  var slides = document.getElementById('slideProj');
+  var outline = document.getElementById('outlineStyle');
+  if (!slides.disabled) {
+    slides.disabled = true;
+    outline.disabled = false;
+    s5mode = false;
+    fontSize('1em');
+    for (var n = 0; n < smax; n++) {
+      var slide = slideColl[n];
+      slide.style.visibility = 'visible';
+    }
+  } else {
+    slides.disabled = false;
+    outline.disabled = true;
+    s5mode = true;
+    fontScale();
+    for (var n = 0; n < smax; n++) {
+      var slide = slideColl[n];
+      slide.style.visibility = 'hidden';
+    }
+    slideColl[snum].style.visibility = 'visible';
+  }
 }
 
 function showHide(action) {
-	var obj = GetElementsWithClassName('*','hideme')[0];
-	switch (action) {
-	case 's': obj.style.visibility = 'visible'; break;
-	case 'h': obj.style.visibility = 'hidden'; break;
-	case 'k':
-		if (obj.style.visibility != 'visible') {
-			obj.style.visibility = 'visible';
-		} else {
-			obj.style.visibility = 'hidden';
-		}
-	break;
-	}
+  var obj = GetElementsWithClassName('*','hideme')[0];
+  switch (action) {
+  case 's': obj.style.visibility = 'visible'; break;
+  case 'h': obj.style.visibility = 'hidden'; break;
+  case 'k':
+    if (obj.style.visibility != 'visible') {
+      obj.style.visibility = 'visible';
+    } else {
+      obj.style.visibility = 'hidden';
+    }
+  break;
+  }
 }
 
 // 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/)
 function keys(key) {
-	if (!key) {
-		key = event;
-		key.which = key.keyCode;
-	}
-	if (key.which == 84) {
-		toggle();
-		return;
-	}
-	if (s5mode) {
-		switch (key.which) {
-			case 10: // return
-			case 13: // enter
-				if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
-				if (key.target && isParentOrSelf(key.target, 'controls')) return;
-				if(number != undef) {
-					goTo(number);
-					break;
-				}
-			case 32: // spacebar
-			case 34: // page down
-			case 39: // rightkey
-			case 40: // downkey
-				if(number != undef) {
-					go(number);
-				} else if (!incrementals[snum] || incpos >= incrementals[snum].length) {
-					go(1);
-				} else {
-					subgo(1);
-				}
-				break;
-			case 33: // page up
-			case 37: // leftkey
-			case 38: // upkey
-				if(number != undef) {
-					go(-1 * number);
-				} else if (!incrementals[snum] || incpos <= 0) {
-					go(-1);
-				} else {
-					subgo(-1);
-				}
-				break;
-			case 36: // home
-				goTo(0);
-				break;
-			case 35: // end
-				goTo(smax-1);
-				break;
-			case 67: // c
-				showHide('k');
-				break;
-		}
-		if (key.which < 48 || key.which > 57) {
-			number = undef;
-		} else {
-			if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
-			if (key.target && isParentOrSelf(key.target, 'controls')) return;
-			number = (((number != undef) ? number : 0) * 10) + (key.which - 48);
-		}
-	}
-	return false;
+  if (!key) {
+    key = event;
+    key.which = key.keyCode;
+  }
+  if (key.which == 84) {
+    toggle();
+    return;
+  }
+  if (s5mode) {
+    switch (key.which) {
+      case 10: // return
+      case 13: // enter
+        if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+        if (key.target && isParentOrSelf(key.target, 'controls')) return;
+        if(number != undef) {
+          goTo(number);
+          break;
+        }
+      case 32: // spacebar
+      case 34: // page down
+      case 39: // rightkey
+      case 40: // downkey
+        if(number != undef) {
+          go(number);
+        } else if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+          go(1);
+        } else {
+          subgo(1);
+        }
+        break;
+      case 33: // page up
+      case 37: // leftkey
+      case 38: // upkey
+        if(number != undef) {
+          go(-1 * number);
+        } else if (!incrementals[snum] || incpos <= 0) {
+          go(-1);
+        } else {
+          subgo(-1);
+        }
+        break;
+      case 36: // home
+        goTo(0);
+        break;
+      case 35: // end
+        goTo(smax-1);
+        break;
+      case 67: // c
+        showHide('k');
+        break;
+    }
+    if (key.which < 48 || key.which > 57) {
+      number = undef;
+    } else {
+      if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+      if (key.target && isParentOrSelf(key.target, 'controls')) return;
+      number = (((number != undef) ? number : 0) * 10) + (key.which - 48);
+    }
+  }
+  return false;
 }
 
 function clicker(e) {
-	number = undef;
-	var target;
-	if (window.event) {
-		target = window.event.srcElement;
-		e = window.event;
-	} else target = e.target;
-	if (target.getAttribute('href') != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true;
-	if (!e.which || e.which == 1) {
-		if (!incrementals[snum] || incpos >= incrementals[snum].length) {
-			go(1);
-		} else {
-			subgo(1);
-		}
-	}
+  number = undef;
+  var target;
+  if (window.event) {
+    target = window.event.srcElement;
+    e = window.event;
+  } else target = e.target;
+  if (target.getAttribute('href') != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true;
+  if (!e.which || e.which == 1) {
+    if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+      go(1);
+    } else {
+      subgo(1);
+    }
+  }
 }
 
 function findSlide(hash) {
-	var target = null;
-	var slides = GetElementsWithClassName('*','slide');
-	for (var i = 0; i < slides.length; i++) {
-		var targetSlide = slides[i];
-		if ( (targetSlide.name && targetSlide.name == hash)
-		 || (targetSlide.id && targetSlide.id == hash) ) {
-			target = targetSlide;
-			break;
-		}
-	}
-	while(target != null && target.nodeName != 'BODY') {
-		if (hasClass(target, 'slide')) {
-			return parseInt(target.id.slice(5));
-		}
-		target = target.parentNode;
-	}
-	return null;
+  var target = null;
+  var slides = GetElementsWithClassName('*','slide');
+  for (var i = 0; i < slides.length; i++) {
+    var targetSlide = slides[i];
+    if ( (targetSlide.name && targetSlide.name == hash)
+     || (targetSlide.id && targetSlide.id == hash) ) {
+      target = targetSlide;
+      break;
+    }
+  }
+  while(target != null && target.nodeName != 'BODY') {
+    if (hasClass(target, 'slide')) {
+      return parseInt(target.id.slice(5));
+    }
+    target = target.parentNode;
+  }
+  return null;
 }
 
 function slideJump() {
-	if (window.location.hash == null) return;
-	var sregex = /^#slide(\d+)$/;
-	var matches = sregex.exec(window.location.hash);
-	var dest = null;
-	if (matches != null) {
-		dest = parseInt(matches[1]);
-	} else {
-		dest = findSlide(window.location.hash.slice(1));
-	}
-	if (dest != null)
-		go(dest - snum);
+  if (window.location.hash == null) return;
+  var sregex = /^#slide(\d+)$/;
+  var matches = sregex.exec(window.location.hash);
+  var dest = null;
+  if (matches != null) {
+    dest = parseInt(matches[1]);
+  } else {
+    dest = findSlide(window.location.hash.slice(1));
+  }
+  if (dest != null)
+    go(dest - snum);
 }
 
 function fixLinks() {
-	var thisUri = window.location.href;
-	thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
-	var aelements = document.getElementsByTagName('A');
-	for (var i = 0; i < aelements.length; i++) {
-		var a = aelements[i].href;
-		var slideID = a.match('\#slide[0-9]{1,2}');
-		if ((slideID) && (slideID[0].slice(0,1) == '#')) {
-			var dest = findSlide(slideID[0].slice(1));
-			if (dest != null) {
-				if (aelements[i].addEventListener) {
-					aelements[i].addEventListener("click", new Function("e",
-						"if (document.getElementById('slideProj').disabled) return;" +
-						"go("+dest+" - snum); " +
-						"if (e.preventDefault) e.preventDefault();"), true);
-				} else if (aelements[i].attachEvent) {
-					aelements[i].attachEvent("onclick", new Function("",
-						"if (document.getElementById('slideProj').disabled) return;" +
-						"go("+dest+" - snum); " +
-						"event.returnValue = false;"));
-				}
-			}
-		}
-	}
+  var thisUri = window.location.href;
+  thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
+  var aelements = document.getElementsByTagName('A');
+  for (var i = 0; i < aelements.length; i++) {
+    var a = aelements[i].href;
+    var slideID = a.match('\#slide[0-9]{1,2}');
+    if ((slideID) && (slideID[0].slice(0,1) == '#')) {
+      var dest = findSlide(slideID[0].slice(1));
+      if (dest != null) {
+        if (aelements[i].addEventListener) {
+          aelements[i].addEventListener("click", new Function("e",
+            "if (document.getElementById('slideProj').disabled) return;" +
+            "go("+dest+" - snum); " +
+            "if (e.preventDefault) e.preventDefault();"), true);
+        } else if (aelements[i].attachEvent) {
+          aelements[i].attachEvent("onclick", new Function("",
+            "if (document.getElementById('slideProj').disabled) return;" +
+            "go("+dest+" - snum); " +
+            "event.returnValue = false;"));
+        }
+      }
+    }
+  }
 }
 
 function externalLinks() {
-	if (!document.getElementsByTagName) return;
-	var anchors = document.getElementsByTagName('a');
-	for (var i=0; i<anchors.length; i++) {
-		var anchor = anchors[i];
-		if (anchor.getAttribute('href') && hasValue(anchor.rel, 'external')) {
-			anchor.target = '_blank';
-			addClass(anchor,'external');
-		}
-	}
+  if (!document.getElementsByTagName) return;
+  var anchors = document.getElementsByTagName('a');
+  for (var i=0; i<anchors.length; i++) {
+    var anchor = anchors[i];
+    if (anchor.getAttribute('href') && hasValue(anchor.rel, 'external')) {
+      anchor.target = '_blank';
+      addClass(anchor,'external');
+    }
+  }
 }
 
 function createControls() {
-	var controlsDiv = document.getElementById("controls");
-	if (!controlsDiv) return;
-	var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
-	var hideDiv, hideList = '';
-	if (controlVis == 'hidden') {
-		hideDiv = hider;
-	} else {
-		hideList = hider;
-	}
-	controlsDiv.innerHTML = '<form action="#" id="controlForm"' + hideDiv + '>' +
-	'<div id="navLinks">' +
-	'<a accesskey="t" id="toggle" href="javascript:toggle();">Ø<\/a>' +
-	'<a accesskey="z" id="prev" href="javascript:go(-1);">«<\/a>' +
-	'<a accesskey="x" id="next" href="javascript:go(1);">»<\/a>' +
-	'<div id="navList"' + hideList + '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
-	'<\/div><\/form>';
-	if (controlVis == 'hidden') {
-		var hidden = document.getElementById('navLinks');
-	} else {
-		var hidden = document.getElementById('jumplist');
-	}
-	addClass(hidden,'hideme');
+  var controlsDiv = document.getElementById("controls");
+  if (!controlsDiv) return;
+  var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
+  var hideDiv, hideList = '';
+  if (controlVis == 'hidden') {
+    hideDiv = hider;
+  } else {
+    hideList = hider;
+  }
+  controlsDiv.innerHTML = '<form action="#" id="controlForm"' + hideDiv + '>' +
+  '<div id="navLinks">' +
+  '<a accesskey="t" id="toggle" href="javascript:toggle();">Ø<\/a>' +
+  '<a accesskey="z" id="prev" href="javascript:go(-1);">«<\/a>' +
+  '<a accesskey="x" id="next" href="javascript:go(1);">»<\/a>' +
+  '<div id="navList"' + hideList + '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
+  '<\/div><\/form>';
+  if (controlVis == 'hidden') {
+    var hidden = document.getElementById('navLinks');
+  } else {
+    var hidden = document.getElementById('jumplist');
+  }
+  addClass(hidden,'hideme');
 }
 
 function fontScale() {  // causes layout problems in FireFox that get fixed if browser's Reload is used; same may be true of other Gecko-based browsers
-	if (!s5mode) return false;
-	var vScale = 22;  // both yield 32 (after rounding) at 1024x768
-	var hScale = 32;  // perhaps should auto-calculate based on theme's declared value?
-	if (window.innerHeight) {
-		var vSize = window.innerHeight;
-		var hSize = window.innerWidth;
-	} else if (document.documentElement.clientHeight) {
-		var vSize = document.documentElement.clientHeight;
-		var hSize = document.documentElement.clientWidth;
-	} else if (document.body.clientHeight) {
-		var vSize = document.body.clientHeight;
-		var hSize = document.body.clientWidth;
-	} else {
-		var vSize = 700;  // assuming 1024x768, minus chrome and such
-		var hSize = 1024; // these do not account for kiosk mode or Opera Show
-	}
-	var newSize = Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));
-	fontSize(newSize + 'px');
-	if (isGe) {  // hack to counter incremental reflow bugs
-		var obj = document.getElementsByTagName('body')[0];
-		obj.style.display = 'none';
-		obj.style.display = 'block';
-	}
+  if (!s5mode) return false;
+  var vScale = 22;  // both yield 32 (after rounding) at 1024x768
+  var hScale = 32;  // perhaps should auto-calculate based on theme's declared value?
+  if (window.innerHeight) {
+    var vSize = window.innerHeight;
+    var hSize = window.innerWidth;
+  } else if (document.documentElement.clientHeight) {
+    var vSize = document.documentElement.clientHeight;
+    var hSize = document.documentElement.clientWidth;
+  } else if (document.body.clientHeight) {
+    var vSize = document.body.clientHeight;
+    var hSize = document.body.clientWidth;
+  } else {
+    var vSize = 700;  // assuming 1024x768, minus chrome and such
+    var hSize = 1024; // these do not account for kiosk mode or Opera Show
+  }
+  var newSize = Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));
+  fontSize(newSize + 'px');
+  if (isGe) {  // hack to counter incremental reflow bugs
+    var obj = document.getElementsByTagName('body')[0];
+    obj.style.display = 'none';
+    obj.style.display = 'block';
+  }
 }
 
 function fontSize(value) {
-	if (!(s5ss = document.getElementById('s5ss'))) {
-		if (!isIE) {
-			document.getElementsByTagName('head')[0].appendChild(s5ss = document.createElement('style'));
-			s5ss.setAttribute('media','screen, projection');
-			s5ss.setAttribute('id','s5ss');
-		} else {
-			document.createStyleSheet();
-			document.s5ss = document.styleSheets[document.styleSheets.length - 1];
-		}
-	}
-	if (!isIE) {
-		while (s5ss.lastChild) s5ss.removeChild(s5ss.lastChild);
-		s5ss.appendChild(document.createTextNode('body {font-size: ' + value + ' !important;}'));
-	} else {
-		document.s5ss.addRule('body','font-size: ' + value + ' !important;');
-	}
+  if (!(s5ss = document.getElementById('s5ss'))) {
+    if (!isIE) {
+      document.getElementsByTagName('head')[0].appendChild(s5ss = document.createElement('style'));
+      s5ss.setAttribute('media','screen, projection');
+      s5ss.setAttribute('id','s5ss');
+    } else {
+      document.createStyleSheet();
+      document.s5ss = document.styleSheets[document.styleSheets.length - 1];
+    }
+  }
+  if (!isIE) {
+    while (s5ss.lastChild) s5ss.removeChild(s5ss.lastChild);
+    s5ss.appendChild(document.createTextNode('body {font-size: ' + value + ' !important;}'));
+  } else {
+    document.s5ss.addRule('body','font-size: ' + value + ' !important;');
+  }
 }
 
 function notOperaFix() {
-	slideCSS = document.getElementById('slideProj').href;
-	var slides = document.getElementById('slideProj');
-	var outline = document.getElementById('outlineStyle');
-	slides.setAttribute('media','screen');
-	outline.disabled = true;
-	if (isGe) {
-		slides.setAttribute('href','null');   // Gecko fix
-		slides.setAttribute('href',slideCSS); // Gecko fix
-	}
-	if (isIE && document.styleSheets && document.styleSheets[0]) {
-		document.styleSheets[0].addRule('img', 'behavior: url(ui/default/iepngfix.htc)');
-		document.styleSheets[0].addRule('div', 'behavior: url(ui/default/iepngfix.htc)');
-		document.styleSheets[0].addRule('.slide', 'behavior: url(ui/default/iepngfix.htc)');
-	}
+  slideCSS = document.getElementById('slideProj').href;
+  var slides = document.getElementById('slideProj');
+  var outline = document.getElementById('outlineStyle');
+  slides.setAttribute('media','screen');
+  outline.disabled = true;
+  if (isGe) {
+    slides.setAttribute('href','null');   // Gecko fix
+    slides.setAttribute('href',slideCSS); // Gecko fix
+  }
+  if (isIE && document.styleSheets && document.styleSheets[0]) {
+    document.styleSheets[0].addRule('img', 'behavior: url(ui/default/iepngfix.htc)');
+    document.styleSheets[0].addRule('div', 'behavior: url(ui/default/iepngfix.htc)');
+    document.styleSheets[0].addRule('.slide', 'behavior: url(ui/default/iepngfix.htc)');
+  }
 }
 
 function getIncrementals(obj) {
-	var incrementals = new Array();
-	if (!obj) 
-		return incrementals;
-	var children = obj.childNodes;
-	for (var i = 0; i < children.length; i++) {
-		var child = children[i];
-		if (hasClass(child, 'incremental')) {
-			if (child.nodeName == 'OL' || child.nodeName == 'UL') {
-				removeClass(child, 'incremental');
-				for (var j = 0; j < child.childNodes.length; j++) {
-					if (child.childNodes[j].nodeType == 1) {
-						addClass(child.childNodes[j], 'incremental');
-					}
-				}
-			} else {
-				incrementals[incrementals.length] = child;
-				removeClass(child,'incremental');
-			}
-		}
-		if (hasClass(child, 'show-first')) {
-			if (child.nodeName == 'OL' || child.nodeName == 'UL') {
-				removeClass(child, 'show-first');
-				if (child.childNodes[isGe].nodeType == 1) {
-					removeClass(child.childNodes[isGe], 'incremental');
-				}
-			} else {
-				incrementals[incrementals.length] = child;
-			}
-		}
-		incrementals = incrementals.concat(getIncrementals(child));
-	}
-	return incrementals;
+  var incrementals = new Array();
+  if (!obj)
+    return incrementals;
+  var children = obj.childNodes;
+  for (var i = 0; i < children.length; i++) {
+    var child = children[i];
+    if (hasClass(child, 'incremental')) {
+      if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+        removeClass(child, 'incremental');
+        for (var j = 0; j < child.childNodes.length; j++) {
+          if (child.childNodes[j].nodeType == 1) {
+            addClass(child.childNodes[j], 'incremental');
+          }
+        }
+      } else {
+        incrementals[incrementals.length] = child;
+        removeClass(child,'incremental');
+      }
+    }
+    if (hasClass(child, 'show-first')) {
+      if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+        removeClass(child, 'show-first');
+        if (child.childNodes[isGe].nodeType == 1) {
+          removeClass(child.childNodes[isGe], 'incremental');
+        }
+      } else {
+        incrementals[incrementals.length] = child;
+      }
+    }
+    incrementals = incrementals.concat(getIncrementals(child));
+  }
+  return incrementals;
 }
 
 function createIncrementals() {
-	var incrementals = new Array();
-	for (var i = 0; i < smax; i++) {
-		incrementals[i] = getIncrementals(document.getElementById('slide'+i));
-	}
-	return incrementals;
+  var incrementals = new Array();
+  for (var i = 0; i < smax; i++) {
+    incrementals[i] = getIncrementals(document.getElementById('slide'+i));
+  }
+  return incrementals;
 }
 
 function defaultCheck() {
-	var allMetas = document.getElementsByTagName('meta');
-	for (var i = 0; i< allMetas.length; i++) {
-		if (allMetas[i].name == 'defaultView') {
-			defaultView = allMetas[i].content;
-		}
-		if (allMetas[i].name == 'controlVis') {
-			controlVis = allMetas[i].content;
-		}
-	}
+  var allMetas = document.getElementsByTagName('meta');
+  for (var i = 0; i< allMetas.length; i++) {
+    if (allMetas[i].name == 'defaultView') {
+      defaultView = allMetas[i].content;
+    }
+    if (allMetas[i].name == 'controlVis') {
+      controlVis = allMetas[i].content;
+    }
+  }
 }
 
 // Key trap fix, new function body for trap()
 function trap(e) {
-	if (!e) {
-		e = event;
-		e.which = e.keyCode;
-	}
-	try {
-		modifierKey = e.ctrlKey || e.altKey || e.metaKey;
-	}
-	catch(e) {
-		modifierKey = false;
-	}
-	return modifierKey || e.which == 0;
+  if (!e) {
+    e = event;
+    e.which = e.keyCode;
+  }
+  try {
+    modifierKey = e.ctrlKey || e.altKey || e.metaKey;
+  }
+  catch(e) {
+    modifierKey = false;
+  }
+  return modifierKey || e.which == 0;
 }
 
 function startup() {
-	defaultCheck();
-	if (!isOp) 
-		createControls();
-	slideLabel();
-	fixLinks();
-	externalLinks();
-	fontScale();
-	if (!isOp) {
-		notOperaFix();
-		incrementals = createIncrementals();
-		slideJump();
-		if (defaultView == 'outline') {
-			toggle();
-		}
-		document.onkeyup = keys;
-		document.onkeypress = trap;
-		document.onclick = clicker;
-	}
+  defaultCheck();
+  if (!isOp)
+    createControls();
+  slideLabel();
+  fixLinks();
+  externalLinks();
+  fontScale();
+  if (!isOp) {
+    notOperaFix();
+    incrementals = createIncrementals();
+    slideJump();
+    if (defaultView == 'outline') {
+      toggle();
+    }
+    document.onkeyup = keys;
+    document.onkeypress = trap;
+    document.onclick = clicker;
+  }
 }
 
 window.onload = startup;
@@ -752,5 +752,5 @@ window.onresize = function(){setTimeout('fontScale()', 50);}
 
 EOF
 
-end 
+end
 
diff --git a/lib/maruku/output/s5/to_s5.rb b/lib/maruku/output/s5/to_s5.rb
index d2dd9f7..c15a656 100644
--- a/lib/maruku/output/s5/to_s5.rb
+++ b/lib/maruku/output/s5/to_s5.rb
@@ -1,138 +1,118 @@
-# This module groups all functions related to HTML export.
-module MaRuKu
+require 'maruku/output/to_html'
 
-begin
-        require 'rexml/formatters/pretty'
-        require 'rexml/formatters/default'
-        $rexml_new_version = true
-rescue LoadError
-        $rexml_new_version = false      
-end
-	 
-	class MDDocument
-
-	def s5_theme
-	  html_escape(self.attributes[:slide_theme] || "default")
-	end
-
-	def  html_escape(string)
-	  string.gsub( /&/, "&" ).
-	         gsub( /</, "<" ).
-	         gsub( />/, ">" ).
-	         gsub( /'/, "'" ).
-	         gsub( /"/, """ )
-	end
-		
-	# Render as an HTML fragment (no head, just the content of BODY). (returns a string)
-	def to_s5(context={})
-		indent       = context[:indent]       || -1
-		ie_hack      = !context[:ie_hack].kind_of?(FalseClass)
-		content_only = !context[:content_only].kind_of?(FalseClass)
-
-		doc = Document.new(nil,{:respect_whitespace =>:all})
-
-		if content_only
-			body = Element.new('div', doc)
-		else
-			html = Element.new('html', doc)
-			html.add_namespace('http://www.w3.org/1999/xhtml')
-			html.add_namespace('svg', "http://www.w3.org/2000/svg" )
-
-			head = Element.new('head', html)
-			me = Element.new 'meta', head
-			me.attributes['http-equiv'] = 'Content-type'
-			me.attributes['content'] = 'text/html;charset=utf-8'	
-
-			# Create title element
-			doc_title = self.attributes[:title] || self.attributes[:subject] || ""
-			title = Element.new 'title', head
-				title << Text.new(doc_title)		
-			body = Element.new('body', html)
-			
-		end
-		
-		slide_header = self.attributes[:slide_header]
-		slide_footer = self.attributes[:slide_footer]
-		slide_subfooter = self.attributes[:slide_subfooter]
-		slide_topleft  = self.attributes[:slide_topleft]
-		slide_topright  = self.attributes[:slide_topright]
-		slide_bottomleft  = self.attributes[:slide_bottomleft]
-		slide_bottomright  = self.attributes[:slide_bottomright]
-
-		dummy_layout_slide = 
-		"
-		<div class='layout'>
-		<div id='controls'> </div>
-		<div id='currentSlide'> </div>
-		<div id='header'> #{slide_header}</div>
-		<div id='footer'>
-		<h1>#{slide_footer}</h1>
-		<h2>#{slide_subfooter}</h2>
-		</div>
-		<div class='topleft'> #{slide_topleft}</div>
-		<div class='topright'> #{slide_topright}</div>
-		<div class='bottomleft'> #{slide_bottomleft}</div>
-		<div class='bottomright'> #{slide_bottomright}</div>
-		</div>
+module MaRuKu
+  class MDDocument
+    def s5_theme
+      xtext(self.attributes[:slide_theme] || "default")
+    end
+
+    # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
+    def to_s5(context={})
+      content_only = context[:content_only] != false
+      print_slides = context[:print_slides]
+
+      if content_only
+        body = xelem('div', doc)
+      else
+        html = xelem('html')
+        html['xmlns'] = 'http://www.w3.org/1999/xhtml'
+        html['xmlns:svg'] = "http://www.w3.org/2000/svg"
+        html['xml:lang'] = self.attributes[:lang] || 'en'
+
+        head = xelem('head')
+        html << head
+
+        me = xelem('meta')
+        me['http-equiv'] = 'Content-type'
+        me['content'] = 'text/html;charset=utf-8'
+        head << me
+
+        # Create title element
+        doc_title = self.attributes[:title] || self.attributes[:subject] || ""
+        begin
+          title_content = MaRuKu::HTMLFragment.new(doc_title).to_html
+        rescue
+          title_content = xtext(doc_title)
+        end
+        title = xelem('title') << title_content
+        head << title
+
+        body = xelem('body')
+        html << body
+      end
+
+      slide_header = self.attributes[:slide_header]
+      slide_footer = self.attributes[:slide_footer]
+      slide_subfooter = self.attributes[:slide_subfooter]
+      slide_topleft  = self.attributes[:slide_topleft]
+      slide_topright  = self.attributes[:slide_topright]
+      slide_bottomleft  = self.attributes[:slide_bottomleft]
+      slide_bottomright  = self.attributes[:slide_bottomright]
+
+      dummy_layout_slide = "
+    <div class='layout'>
+    <div id='controls'> </div>
+    <div id='currentSlide'> </div>
+    <div id='header'> #{slide_header}</div>
+    <div id='footer'>
+    <h1>#{slide_footer}</h1>
+    <h2>#{slide_subfooter}</h2>
+    </div>
+    <div class='topleft'> #{slide_topleft}</div>
+    <div class='topright'> #{slide_topright}</div>
+    <div class='bottomleft'> #{slide_bottomleft}</div>
+    <div class='bottomright'> #{slide_bottomright}</div>
+    </div>
                 "
-		body.add_element Document.new(dummy_layout_slide, {:respect_whitespace =>:all}).root
-
-		presentation = Element.new 'div', body
-		presentation.attributes['class'] = 'presentation'
-		
-		first_slide="
-	  <div class='slide'>
-	  <h1> #{self.attributes[:title] ||context[:title]}</h1>
-	  <h2> #{self.attributes[:subtitle] ||context[:subtitle]}</h2>
-	  <h3> #{self.attributes[:author] ||context[:author]}</h3>
-	  <h4> #{self.attributes[:company] ||context[:company]}</h4>
-	  </div>
-		"
-		presentation.add_element Document.new(first_slide).root
-
-		slide_num = 0
-		self.toc.section_children.each do |slide|
-			slide_num += 1
-			@doc.attributes[:doc_prefix] = "s#{slide_num}"
-			
-			puts "Slide #{slide_num}: " + slide.header_element.to_s
-			div = Element.new('div', presentation)
-			div.attributes['class'] = 'slide'
-			
-			h1 = Element.new 'h1', div
-			slide.header_element.children_to_html.each do |e| h1 << e; end
-			
-			array_to_html(slide.immediate_children).each do |e|  div << e  end
-				
-			# render footnotes
-			if @doc.footnotes_order.size > 0
-				div << render_footnotes
-				@doc.footnotes_order = []
-			end
-		end
-
-		xml  = "" 
-		if (content_only)
-		   if $rexml_new_version
-		     formatter = REXML::Formatters::Default.new(ie_hack)
-                     formatter.write(body, xml)
-		   else
-		     body.write(xml,indent,transitive=true,ie_hack);
-		  end
-		else
-		  doc2 = Document.new("<div>"+S5_external+"</div>",{:respect_whitespace =>:all})
-		  doc2.root.children.each{ |child| head << child }
-
-		  add_css_to(head)
-
-		  # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
-		  # containing code.
-		  html.write(xml,indent,transitive=true,ie_hack);
-		  Xhtml11_mathml2_svg11 + xml
-		end
-	end
-
-end 
-
-
+      body <<  dummy_layout_slide
+
+      presentation = xelem('div')
+      presentation['class'] = 'presentation'
+      body << presentation
+
+      first_slide = "
+    <div class='slide'>
+    <h1> #{self.attributes[:title] ||context[:title]}</h1>
+    <h2> #{self.attributes[:subtitle] ||context[:subtitle]}</h2>
+    <h3> #{self.attributes[:author] ||context[:author]}</h3>
+    <h4> #{self.attributes[:company] ||context[:company]}</h4>
+    </div>
+    "
+      presentation << first_slide
+
+      slide_num = 0
+      self.toc.section_children.each do |slide|
+        slide_num += 1
+        @doc.attributes[:doc_prefix] = "s#{slide_num}"
+
+        div = xelem('div')
+        presentation << div
+        div['class'] = 'slide'
+
+        h1 = xelem('h1')
+        puts "Slide #{slide_num}: #{slide.header_element.children_to_html.join}" if print_slides
+        slide.header_element.children_to_html.inject(h1, &:<<)
+        div << h1
+
+        array_to_html(slide.immediate_children).inject(div, &:<<)
+
+        # render footnotes
+        unless @doc.footnotes_order.empty?
+          div << render_footnotes
+          @doc.footnotes_order = []
+        end
+      end
+
+      if content_only
+        xml = body.to_html
+      else
+        head << S5_external
+
+        add_css_to(head)
+
+        xml = html.to_html
+        Xhtml11_mathml2_svg11 + xml
+      end
+    end
+  end
 end
diff --git a/lib/maruku/output/to_html.rb b/lib/maruku/output/to_html.rb
index f6cfcc0..653ba35 100644
--- a/lib/maruku/output/to_html.rb
+++ b/lib/maruku/output/to_html.rb
@@ -1,991 +1,915 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-require 'rexml/document'
-
-begin
-	require 'rexml/formatters/pretty'
-	require 'rexml/formatters/default'
-	$rexml_new_version = true
-rescue LoadError
-	$rexml_new_version = false	
-end
+require 'maruku/string_utils'
+require 'cgi'
 
-class String
-	# A string is rendered into HTML by creating
-	# a REXML::Text node. REXML takes care of all the encoding.
-	def to_html
-		REXML::Text.new(self)
-	end
-end
+# This module groups all functions related to HTML export.
+module MaRuKu::Out::HTML
+
+  # Escape text for use in HTML (content or attributes) by running it through
+  # standard XML escaping (quotes and angle brackets and ampersands)
+  def self.escapeHTML(text)
+    CGI.escapeHTML(text)
+    # TODO: When we drop Rubies < 1.9.3, re-add .gsub(/[^[:print:]\n\r\t]/, '') to
+    # get rid of non-printable control characters.
+  end
+
+  # A simple class to represent an HTML element for output.
+  class HTMLElement
+    attr_accessor :name
+    attr_accessor :attributes
+    attr_accessor :children
+
+    def initialize(name, attr={}, children=[])
+      self.name = name
+      self.attributes = attr || {}
+      self.children = Array(children)
+      children << yield if block_given?
+    end
 
+    def <<(child)
+      children << child if children
+      self
+    end
 
-# This module groups all functions related to HTML export.
-module MaRuKu; module Out; module HTML
-	include REXML
-	
-	# Render as an HTML fragment (no head, just the content of BODY). (returns a string)
-	def to_html(context={})
-		indent = context[:indent] || -1
-		ie_hack = context[:ie_hack] || true
-		
-		div = Element.new 'dummy'
-			children_to_html.each do |e|
-				div << e
-			end
-
-			# render footnotes
-			if @doc.footnotes_order.size > 0
-				div << render_footnotes
-			end
-		
-		doc = Document.new(nil,{:respect_whitespace =>:all})
-		doc << div
-		
-		# REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
-		# containing code.
-		xml =""
-
-		if $rexml_new_version
-			formatter = if indent > -1
-	          REXML::Formatters::Pretty.new( indent, ie_hack )
-	        else
-	          REXML::Formatters::Default.new( ie_hack )
-	        end
-			formatter.write( div, xml)
-		else
-			div.write(xml,indent,transitive=true,ie_hack)
-		end
-
-		xml.gsub!(/\A<dummy>\s*/,'')
-		xml.gsub!(/\s*<\/dummy>\Z/,'')
-		xml.gsub!(/\A<dummy\s*\/>/,'')
-		xml
-	end
-	
-	# Render to a complete HTML document (returns a string)
-	def to_html_document(context={})
-		indent = context[:indent] || -1
-		ie_hack = context[:ie_hack] ||true
-		doc = to_html_document_tree
-		xml  = "" 
-		
-		# REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
-		# containing code.
-		doc.write(xml,indent,transitive=true,ie_hack);
-		
-		Xhtml11_mathml2_svg11 + xml
-	end
-	
-				
-		Xhtml10strict  = 
-"<?xml version='1.0' encoding='utf-8'?>
-<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'
-'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>\n"
-		
-	Xhtml11strict_mathml2 = '<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"
-               "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd" [
-  <!ENTITY mathml "http://www.w3.org/1998/Math/MathML">
-]>
-'
+    def [](key)
+      attributes[key.to_s]
+    end
+
+    def []=(key, value)
+      attributes[key.to_s] = value
+    end
+
+    def add_class(class_name)
+      attributes['class'] = ((attributes['class']||'').split(' ') + [class_name]).join(' ')
+    end
+
+    # These elements have no children and should be rendered with a self-closing tag.
+    # It's not an exhaustive list, but they cover everything we use.
+    SELF_CLOSING = Set.new %w[br hr img link meta]
+
+    def to_html
+      m = "<#{name}"
+      attributes.each do |k, v|
+        m << " #{k.to_s}=\"#{v.to_s}\""
+      end
+
+      if SELF_CLOSING.include? name
+        m << " />"
+      else
+        content = children.map(&:to_s)
+        m << ">" << content.join('') << "</#{name}>"
+      end
+    end
+
+    alias :to_str :to_html
+    alias :to_s :to_html
+  end
+
+  # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
+  def to_html(context={})
+    output = ""
+    children_to_html.each do |e|
+      output << e.to_s
+    end
 
-Xhtml11_mathml2_svg11 = 
-'<?xml version="1.0" encoding="utf-8"?>
+    # render footnotes
+    unless @doc.footnotes_order.empty?
+      output << render_footnotes
+    end
+
+    output
+  end
+
+  Xhtml11_mathml2_svg11 =
+    '<?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC
     "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
     "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
 '
-	
-	
-	def xml_newline() Text.new("\n") end
-		
-
-=begin maruku_doc
-Attribute: title
-Scope: document
-
-Sets the title of the document.
-If a title is not specified, the first header will be used.
-
-These should be equivalent:
-
-	Title: my document
-
-	Content
-
-and
-
-	my document
-	===========
-
-	Content
-
-In both cases, the title is set to "my document".
-=end
-
-=begin maruku_doc
-Attribute: doc_prefix
-Scope: document
-
-String to disambiguate footnote links.
-=end
-
-
-=begin maruku_doc
-Attribute: subject
-Scope: document
-
-Synonim for `title`.
-=end
-
-
-	# Render to an HTML fragment (returns a REXML document tree)
-	def to_html_tree
-		div = Element.new 'div'
-			div.attributes['class'] = 'maruku_wrapper_div'
-				children_to_html.each do |e|
-						  div << e
-				end
-
-				# render footnotes
-				if @doc.footnotes_order.size > 0
-						  div << render_footnotes
-				end
-
-		 doc = Document.new(nil,{:respect_whitespace =>:all})
-		 doc << div
-	end
-
-=begin maruku_doc
-Attribute: css
-Scope: document
-Output: HTML
-Summary: Activates CSS stylesheets for HTML.
-
-`css` should be a space-separated list of urls.
-
-Example:
-
-	CSS: style.css math.css
-
-=end
-
-	METAS = %w{description keywords author revised}
-
-	# Render to a complete HTML document (returns a REXML document tree)
-	def to_html_document_tree
-		doc = Document.new(nil,{:respect_whitespace =>:all})
-	#	doc << XMLDecl.new
-		
-		root = Element.new('html', doc)
-		root.add_namespace('http://www.w3.org/1999/xhtml')
-		root.add_namespace('svg', "http://www.w3.org/2000/svg" )
-		lang = self.attributes[:lang] || 'en'
-		root.attributes['xml:lang'] = lang
-		
-		root << xml_newline
-		head = Element.new 'head', root
-		
-			#<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
-			me = Element.new 'meta', head
-			me.attributes['http-equiv'] = 'Content-type'
-#			me.attributes['content'] = 'text/html;charset=utf-8'	
-			me.attributes['content'] = 'application/xhtml+xml;charset=utf-8'	
-		
-			METAS.each do |m|
-				if value = self.attributes[m.to_sym]
-					meta = Element.new 'meta', head
-					meta.attributes['name'] = m
-					meta.attributes['content'] = value.to_s
-				end
-			end
-			
-			
-			self.attributes.each do |k,v|
-				if k.to_s =~ /\Ameta-(.*)\Z/
-					meta = Element.new 'meta', head
-					meta.attributes['name'] = $1
-					meta.attributes['content'] = v.to_s
-				end
-			end
-			
-
-			
-			# Create title element
-			doc_title = self.attributes[:title] || self.attributes[:subject] || ""
-			title = Element.new 'title', head
-				title << Text.new(doc_title)
-							
-			add_css_to(head)
-			
-		
-		root << xml_newline
-		
-		body = Element.new 'body'
-		
-			children_to_html.each do |e|
-				body << e
-			end
-
-			# render footnotes
-			if @doc.footnotes_order.size > 0
-				body << render_footnotes
-			end
-			
-			# When we are rendering a whole document, we add a signature 
-			# at the bottom. 
-			if get_setting(:maruku_signature)
-				body << maruku_html_signature 
-			end
-			
-		root << body
-		
-		doc
-	end
-
-	def add_css_to(head)
-		if css_list = self.attributes[:css]
-			css_list.split.each do |css|
-			# <link type="text/css" rel="stylesheet" href="..." />
-			link = Element.new 'link'
-			link.attributes['type'] = 'text/css'
-			link.attributes['rel'] = 'stylesheet'
-			link.attributes['href'] = css
-			head << link 
-			head << xml_newline
-			end
-		end
-	end
-	
-	# returns "st","nd","rd" or "th" as appropriate
-	def day_suffix(day)
-		s = {
-			1 => 'st',
-			2 => 'nd',
-			3 => 'rd',
-			21 => 'st',
-			22 => 'nd',
-			23 => 'rd',
-			31 => 'st'
-		}
-		return s[day] || 'th';
-	end
-
-	# formats a nice date
-	def nice_date
-		t = Time.now
-		t.strftime(" at %H:%M on ")+
-		t.strftime("%A, %B %d")+
-		day_suffix(t.day)+
-		t.strftime(", %Y")
-	end
-	
-	def maruku_html_signature		
-		div = Element.new 'div'
-			div.attributes['class'] = 'maruku_signature'
-			Element.new 'hr', div
-			span = Element.new 'span', div
-				span.attributes['style'] = 'font-size: small; font-style: italic'
-				span << Text.new('Created by ')
-				a = Element.new('a', span)
-					a.attributes['href'] = 'http://maruku.rubyforge.org'
-					a.attributes['title'] = 'Maruku: a Markdown-superset interpreter for Ruby'
-					a << Text.new('Maruku')
-				span << Text.new(nice_date+".")
-		div
-	end
-	
-	def render_footnotes()
-		div = Element.new 'div'
-		div.attributes['class'] = 'footnotes'
-		div <<  Element.new('hr')
-			ol = Element.new 'ol'
-			@doc.footnotes_order.each_with_index do |fid, i| num = i+1
-				f = self.footnotes[fid]
-				if f
-					li = f.wrap_as_element('li')
-					li.attributes['id'] = "#{get_setting(:doc_prefix)}fn:#{num}"
-					
-					a = Element.new 'a'
-						a.attributes['href'] = "\##{get_setting(:doc_prefix)}fnref:#{num}"
-						a.attributes['rev'] = 'footnote'
-						a<< Text.new('↩', true, nil, true)
-					li.insert_after(li.children.last, a)
-					ol << li
-				else
-					maruku_error "Could not find footnote id '#{fid}' among ["+
-					 self.footnotes.keys.map{|s|"'"+s+"'"}.join(', ')+"]."
-				end
-			end
-		div << ol
-		div
-	end
-
-
-	def to_html_hrule; create_html_element 'hr' end
-	def to_html_linebreak; Element.new 'br' end
-
-	# renders children as html and wraps into an element of given name
-	# 
-	# Sets 'id' if meta is set
-	def wrap_as_element(name, attributes_to_copy=[])
-		m = create_html_element(name, attributes_to_copy)
-			children_to_html.each do |e| m << e; end
-			
-#			m << Comment.new( "{"+self.al.to_md+"}") if not self.al.empty?
-#			m << Comment.new( @attributes.inspect) if not @attributes.empty?
-		m
-	end
-	
-=begin maruku_doc
-Attribute: id
-Scope: element
-Output: LaTeX, HTML
-
-It is copied as a standard HTML attribute.
-
-Moreover, it used as a label name for hyperlinks in both HTML and
-in PDF.
-
-=end
-
-=begin maruku_doc
-Attribute: class
-Scope: element
-Output: HTML
-
-It is copied as a standard HTML attribute.
-=end
-
-=begin maruku_doc
-Attribute: style
-Scope: element
-Output: HTML
-
-It is copied as a standard HTML attribute.
-=end
-	
-		
-	
-	
-	
-	HTML4Attributes = {}
-	
-	coreattrs = [:id, :class, :style, :title]
-	i18n = [:lang, 'xml:lang'.to_sym]
-	events = [
-		:onclick, :ondblclick, :onmousedown, :onmouseup, :onmouseover, 
-		:onmousemove, :onmouseout,
-		:onkeypress, :onkeydown, :onkeyup]	
-	attrs = coreattrs + i18n + events
-	cellhalign = [:align, :char, :charoff]
-	cellvalign = [:valign]
-	[
-		['body', attrs + [:onload, :onunload]],
-		['address', attrs],
-		['div', attrs],
-		['a', attrs+[:charset, :type, :name, :rel, :rev, :accesskey, :shape, :coords, :tabindex, 
-			:onfocus,:onblur]],
-		['img', attrs + [:longdesc, :name, :height, :width, :alt] ],
-		['p', attrs],
-		[['h1','h2','h3','h4','h5','h6'], attrs], 
-		[['pre'], attrs],
-		[['q', 'blockquote'], attrs+[:cite]],
-		[['ins','del'], attrs+[:cite,:datetime]],
-		[['ol','ul','li'], attrs],
-		['table',attrs+[:summary, :width, :frame, :rules, :border, :cellspacing, :cellpadding]],
-		['caption',attrs],	
-		[['colgroup','col'],attrs+[:span, :width]+cellhalign+cellvalign],
-		[['thead','tbody','tfoot'], attrs+cellhalign+cellvalign],
-		[['td','td','th'], attrs+[:abbr, :axis, :headers, :scope, :rowspan, :colspan, :cellvalign, :cellhalign]],
-		
-		# altri
-		[['em','code','strong','hr','span','dl','dd','dt'], attrs]
-	].each do |el, a| [*el].each do |e| HTML4Attributes[e] = a end end
-		
-		
-	def create_html_element(name, attributes_to_copy=[])
-		m = Element.new name
-			if atts = HTML4Attributes[name] then 
-				atts.each do |att|
-					if v = @attributes[att] then 
-						m.attributes[att.to_s] = v.to_s 
-					end
-				end
-			else
-			#	puts "not atts for #{name.inspect}"
-			end
-		m
-	end
-
-	
-	def to_html_ul
-		if @attributes[:toc]
-			# render toc
-			html_toc = @doc.toc.to_html
-			return html_toc
-		else
-			add_ws  wrap_as_element('ul')               
-		end
-	end
-	
-	
-	def to_html_paragraph; add_ws wrap_as_element('p')                end
-	def to_html_ol;        add_ws wrap_as_element('ol')        end
-	def to_html_li;        add_ws wrap_as_element('li')        end
-	def to_html_li_span;   add_ws wrap_as_element('li')        end
-	def to_html_quote;     add_ws wrap_as_element('blockquote')  end
-	def to_html_strong;    wrap_as_element('strong')           end
-	def to_html_emphasis;  wrap_as_element('em')               end
-
-=begin maruku_doc
-Attribute: use_numbered_headers
-Scope: document
-Summary: Activates the numbering of headers.
-
-If `true`, section headers will be numbered.
-
-In LaTeX export, the numbering of headers is managed
-by Maruku, to have the same results in both HTML and LaTeX.
-=end
-
-	# nil if not applicable, else string
-	def section_number
-		return nil if not get_setting(:use_numbered_headers)
-		
-		n = @attributes[:section_number]
-		if n && (not n.empty?)
-			 n.join('.')+". "
-		else
-			nil
-		end
-	end
-	
-	# nil if not applicable, else SPAN element
-	def render_section_number
-		# if we are bound to a section, add section number
-		if num = section_number
-			span = Element.new 'span'
-			span.attributes['class'] = 'maruku_section_number'
-			span << Text.new(section_number)
-			span
-		else
-			nil
-		end
-	end
-	
-	def to_html_header
-		element_name = "h#{self.level}" 
-		h = wrap_as_element element_name
-		
-		if span = render_section_number
-			h.insert_before(h.children.first, span)
-		end
-		add_ws h
-	end
-
-	def source2html(source)
-#		source = source.gsub(/&/,'&')
-		source = Text.normalize(source)
-		source = source.gsub(/\'/,''') # IE bug
-		source = source.gsub(/'/,''') # IE bug
-		Text.new(source, true, nil, true )
-	end
-		
-=begin maruku_doc
-Attribute: html_use_syntax
-Scope: global, document, element
-Output: HTML
-Summary: Enables the use of the `syntax` package.
-Related: lang, code_lang
-Default: <?mrk md_code(Globals[:html_use_syntax].to_s) ?>
-
-If true, the `syntax` package is used. It supports the `ruby` and `xml`
-languages. Remember to set the `lang` attribute of the code block.
-
-Examples:
-
-		require 'maruku'
-	{:lang=ruby html_use_syntax=true}
-
-and 
-	
-		<div style="text-align:center">Div</div>
-	{:lang=html html_use_syntax=true}
-
-produces:
-
-	require 'maruku'
-{:lang=ruby html_use_syntax=true}
-
-and
-
-	<div style="text-align:center">Div</div>
-{:lang=html html_use_syntax=true}
-
-=end
-
-	$syntax_loaded = false
-	def to_html_code; 
-		source = self.raw_code
-
-		lang = self.attributes[:lang] || @doc.attributes[:code_lang] 
-
-		lang = 'xml' if lang=='html'
-
-		use_syntax = get_setting :html_use_syntax
-		
-		element = 
-		if use_syntax && lang
-			begin
-				if not $syntax_loaded
-					require 'rubygems'
-					require 'syntax'
-					require 'syntax/convertors/html'
-					$syntax_loaded = true
-				end
-				convertor = Syntax::Convertors::HTML.for_syntax lang
-				
-				# eliminate trailing newlines otherwise Syntax crashes
-				source = source.gsub(/\n*\Z/,'')
-				
-				html = convertor.convert( source )
-				html = html.gsub(/\'/,''') # IE bug
-				html = html.gsub(/'/,''') # IE bug
-	#			html = html.gsub(/&/,'&') 
-				
-				code = Document.new(html, {:respect_whitespace =>:all}).root
-				code.name = 'code'
-				code.attributes['class'] = lang
-				code.attributes['lang'] = lang
-				
-				pre = Element.new 'pre'
-				pre << code
-				pre
-			rescue LoadError => e
-				maruku_error "Could not load package 'syntax'.\n"+
-					"Please install it, for example using 'gem install syntax'."
-				to_html_code_using_pre(source)	
-			rescue Object => e
-				maruku_error"Error while using the syntax library for code:\n#{source.inspect}"+
-				 "Lang is #{lang} object is: \n"+
-				  self.inspect + 
-				"\nException: #{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
-				
-				tell_user("Using normal PRE because the syntax library did not work.")
-				to_html_code_using_pre(source)
-			end
-		else
-			to_html_code_using_pre(source)
-		end
-		
-		color = get_setting(:code_background_color)
-		if color != Globals[:code_background_color]
-			element.attributes['style'] = "background-color: #{color};"
-		end
-		add_ws element
-	end
-	
-=begin maruku_doc
-Attribute: code_background_color
-Scope: global, document, element
-Summary: Background color for code blocks.
-
-The format is either a named color (`green`, `red`) or a CSS color
-of the form `#ff00ff`. 
-
-* for **HTML output**, the value is put straight in the `background-color` CSS 
-  property of the block.
-
-* for **LaTeX output**, if it is a named color, it must be a color accepted
-  by the LaTeX `color` packages. If it is of the form `#ff00ff`, Maruku
-  defines a color using the `\color[rgb]{r,g,b}` macro. 
-
-  For example, for `#0000ff`, the macro is called as: `\color[rgb]{0,0,1}`.
-
-=end
-	
-	
-	def to_html_code_using_pre(source)
-		pre = create_html_element  'pre'
-		code = Element.new 'code', pre
-		s = source
-		
-#		s  = s.gsub(/&/,'&')
-		s = Text.normalize(s)
-		s  = s.gsub(/\'/,''') # IE bug
-		s  = s.gsub(/'/,''') # IE bug
-
-		if get_setting(:code_show_spaces) 
-			# 187 = raquo
-			# 160 = nbsp
-			# 172 = not
-			s.gsub!(/\t/,'»'+' '*3)
-			s.gsub!(/ /,'¬')
-		end
-
-		text = Text.new(s, respect_ws=true, parent=nil, raw=true )
-		
-		if lang = self.attributes[:lang]
-			code.attributes['lang'] = lang
-			code.attributes['class'] = lang
-		end
-		code << text
-		pre
-	end
-
-	def to_html_inline_code; 
-		pre =  create_html_element 'code'
-			source = self.raw_code
-			pre << source2html(source) 
-			
-			color = get_setting(:code_background_color)
-			if color != Globals[:code_background_color]
-				pre.attributes['style'] = "background-color: #{color};"+(pre.attributes['style']||"")
-			end
-			
-		pre
-	end
-
-	def add_class_to(el, cl)
-		el.attributes['class'] = 
-		if already = el.attributes['class']
-			already + " " + cl
-		else
-			cl
-		end
-	end
-
-	def add_class_to_link(a)
-		return # not ready yet
-		
-		# url = a.attributes['href']
-		# return if not url
-		# 
-		# if url =~ /^#/
-		# 	add_class_to(a, 'maruku-link-samedoc')
-		# elsif url =~ /^http:/
-		# 	add_class_to(a, 'maruku-link-external')
-		# else
-		# 	add_class_to(a, 'maruku-link-local')
-		# end
-		# 	
-#		puts a.attributes['class']
-	end
-	
-	
-	def to_html_immediate_link
-		a =  create_html_element 'a'
-		url = self.url
-		text = url.gsub(/^mailto:/,'') # don't show mailto
-		a << Text.new(text)
-		a.attributes['href'] = url
-		add_class_to_link(a)
-		a
-	end
-	
-	def to_html_link
-		a =  wrap_as_element 'a'
-		id = self.ref_id
-		
-		if ref = @doc.refs[id]
-			url = ref[:url]
-			title = ref[:title]
-			a.attributes['href'] = url if url
-			a.attributes['title'] = title if title
-		else
-			maruku_error "Could not find ref_id = #{id.inspect} for #{self.inspect}\n"+
-				"Available refs are #{@doc.refs.keys.inspect}"
-			tell_user "Not creating a link for ref_id = #{id.inspect}."
-			return wrap_as_element('span')
-		end
-
-#		add_class_to_link(a)
-		return a
-	end
-	
-	def to_html_im_link
-		if url = self.url
-			title = self.title
-			a =  wrap_as_element 'a'
-			a.attributes['href'] = url
-			a.attributes['title'] = title if title
-			return a
-		else
-			maruku_error"Could not find url in #{self.inspect}"
-			tell_user "Not creating a link for ref_id = #{id.inspect}."
-			return wrap_as_element('span')
-		end
-	end
-	
-	def add_ws(e)
-		[Text.new("\n"), e, Text.new("\n")]
-	end
-##### Email address
-	
-	def obfuscate(s)
-		res = ''
-		s.each_byte do |char|
-			res +=  "&#%03d;" % char
-		end
-		res
-	end
-	
-	def to_html_email_address
-		email = self.email
-		a = create_html_element 'a'
-			#a.attributes['href'] = Text.new("mailto:"+obfuscate(email),false,nil,true)
-			#a.attributes.add Attribute.new('href',Text.new(
-			#"mailto:"+obfuscate(email),false,nil,true))
-			# Sorry, for the moment it doesn't work
-			a.attributes['href'] = "mailto:#{email}"
-			
-			a << Text.new(obfuscate(email),false,nil,true)
-		a
-	end
-
-##### Images
-
-	def to_html_image
-		a =  create_html_element 'img'
-		id = self.ref_id
-		if ref = @doc.refs[id]
-			url = ref[:url]
-			title = ref[:title]
-			a.attributes['src'] = url.to_s
-			a.attributes['alt'] = children_to_s 
-		else
-			maruku_error"Could not find id = #{id.inspect} for\n #{self.inspect}"
-			tell_user "Could not create image with ref_id = #{id.inspect};"+
-				 " Using SPAN element as replacement."
-				return wrap_as_element('span')
-		end
-		return a
-	end
-	
-	def to_html_im_image
-		if not url = self.url
-			maruku_error "Image with no url: #{self.inspect}"
-			tell_user "Could not create image with ref_id = #{id.inspect};"+
-				" Using SPAN element as replacement."
-			return wrap_as_element('span')
-		end
-		title = self.title
-		a =  create_html_element 'img'
-			a.attributes['src'] = url.to_s
-			a.attributes['alt'] = children_to_s 
-		return a
-	end
-
-=begin maruku_doc
-Attribute: filter_html
-Scope: document
-
-If true, raw HTML is discarded from the output.
-
-=end
-
-	def to_html_raw_html
-		return [] if get_setting(:filter_html)
-		
-		raw_html = self.raw_html
-		if rexml_doc = @parsed_html
-			root = rexml_doc.root
-			if root.nil?
-				s = "Bug in REXML: root() of Document is nil: \n#{rexml_doc.inspect}\n"+
-				"Raw HTML:\n#{raw_html.inspect}"
-				maruku_error s
-				tell_user 'The REXML version you have has a bug, omitting HTML'
-				div = Element.new 'div'
-				#div << Text.new(s)
-				return div
-			end
-			
-			# copies the @children array (FIXME is it deep?)
-			elements =  root.to_a 
-			return elements
-		else # invalid
-			# Creates red box with offending HTML
-			tell_user "Wrapping bad html in a PRE with class 'markdown-html-error'\n"+
-				add_tabs(raw_html,1,'|')
-			pre = Element.new('pre')
-			pre.attributes['style'] = 'border: solid 3px red; background-color: pink'
-			pre.attributes['class'] = 'markdown-html-error'
-			pre << Text.new("REXML could not parse this XML/HTML: \n#{raw_html}", true)
-			return pre
-		end
-	end
-
-	def to_html_abbr
-		abbr = Element.new 'abbr'
-		abbr << Text.new(children[0])
-		abbr.attributes['title'] = self.title if self.title
-		abbr
-	end
-	
-	def to_html_footnote_reference
-		id = self.footnote_id
-		
-		# save the order of used footnotes
-		order = @doc.footnotes_order
-		
-		if order.include? id
-		  # footnote has already been used
-		  return []
-	  end
-	  
-	  if not @doc.footnotes[id]
-	    return []
-    end
-	  
-		# take next number
-		order << id
-		
-		#num = order.size; 
-		num = order.index(id) + 1
-		  
-		sup = Element.new 'sup'
-		sup.attributes['id'] = "#{get_setting(:doc_prefix)}fnref:#{num}"
-			a = Element.new 'a'
-			a << Text.new(num.to_s)
-			a.attributes['href'] = "\##{get_setting(:doc_prefix)}fn:#{num}"
-			a.attributes['rel'] = 'footnote'
-		sup << a
-			
-		sup
-	end
-	
-## Definition lists ###
-	def to_html_definition_list() add_ws wrap_as_element('dl') end
-	def to_html_definition() children_to_html end
-	def to_html_definition_term() add_ws wrap_as_element('dt') end
-	def to_html_definition_data() add_ws wrap_as_element('dd') end	
-
-	# FIXME: Ugly code
-	def to_html_table
-		align = self.align
-		num_columns = align.size
-
-		head = @children.slice(0, num_columns)
-		rows = []
-		i = num_columns
-		while i<@children.size
-			rows << @children.slice(i, num_columns)
-			i += num_columns
-		end
-		
-		table = create_html_element 'table'
-			thead = Element.new 'thead'
-			tr = Element.new 'tr'
-				array_to_html(head).each do |x| tr<<x end
-			thead << tr
-			table << thead
-			
-			tbody = Element.new 'tbody'
-			rows.each do |row|
-				tr = Element.new 'tr'
-					array_to_html(row).each_with_index do |x,i| 
-						x.attributes['style'] ="text-align: #{align[i].to_s};" 
-						tr<<x 
-					end
-						
-				tbody << tr << Text.new("\n")
-			end
-			table << tbody
-		table
-	end
-	
-	def to_html_head_cell; wrap_as_element('th') end
-	def to_html_cell
-		if @attributes[:scope]
-			wrap_as_element('th', [:scope])
-		else
-			wrap_as_element('td')
-		end
- 	end
-	
-	def to_html_entity 
-		MaRuKu::Out::Latex.need_entity_table
-      
-		entity_name = self.entity_name
-		
-		if (e = MaRuKu::Out::Latex::ENTITY_TABLE[entity_name]) && e.html_num
-			entity_name = e.html_num
-		end
-		
-		# Fix for Internet Explorer
-		if entity_name == 'apos'
-			entity_name = 39
-		end
-
-		
-		if entity_name.kind_of? Fixnum
-#			Entity.new(entity_name)
-			Text.new('&#%d;' % [entity_name],  false, nil, true)
-		else
-			Text.new('&%s;' % [entity_name],  false, nil, true)
-		end
-	end
-
-	def to_html_xml_instr
-		target = self.target || ''
-		code = self.code || ''
-		REXML::Instruction.new(target, code)
-	end
-
-	# Convert each child to html
-	def children_to_html
-		array_to_html(@children)
-	end
-
-	def array_to_html(array)
-		e = []
-		array.each do |c|
-			method = c.kind_of?(MDElement) ? 
-			   "to_html_#{c.node_type}" : "to_html"
-
-			if not c.respond_to?(method)
-				#raise "Object does not answer to #{method}: #{c.class} #{c.inspect}"
-				next
-			end
-
-			h =  c.send(method)
-
-			if h.nil?
-				raise "Nil html created by method  #{method}:\n#{h.inspect}\n"+
-				" for object #{c.inspect[0,300]}"
-			end
-
-			if h.kind_of?Array
-				e = e + h #h.each do |hh| e << hh end
-			else
-				e << h
-			end
-		end
-		e
-	end
-
-	def to_html_ref_definition; [] end
-	def to_latex_ref_definition; [] end
-
-end # HTML
-end # out
-end # MaRuKu
+
+  # Render to a complete HTML document (returns a string)
+  def to_html_document(context={})
+    doc = to_html_document_tree
+
+    xml = doc.to_s
+    Xhtml11_mathml2_svg11 + xml
+  end
+
+  # Helper to create a text node
+  def xtext(text)
+    MaRuKu::Out::HTML.escapeHTML(text)
+  end
+
+  # Helper to create an element
+  def xelem(type)
+    HTMLElement.new(type)
+  end
+
+  def xml_newline
+    "\n"
+  end
+
+  #=begin maruku_doc
+  # Attribute: title
+  # Scope: document
+  #
+  # Sets the title of the document.
+  # If a title is not specified, the first header will be used.
+  #
+  # These should be equivalent:
+  #
+  #   Title: my document
+  #
+  #   Content
+  #
+  # and
+  #
+  #   my document
+  #   ===========
+  #
+  #   Content
+  #
+  # In both cases, the title is set to "my document".
+  #=end
+
+  #=begin maruku_doc
+  # Attribute: doc_prefix
+  # Scope: document
+  #
+  # String to disambiguate footnote links.
+  #=end
+
+
+  #=begin maruku_doc
+  # Attribute: subject
+  # Scope: document
+
+  # Synonym for `title`.
+  #=end
+
+  #=begin maruku_doc
+  # Attribute: css
+  # Scope: document
+  # Output: HTML
+  # Summary: Activates CSS stylesheets for HTML.
+  #
+  # `css` should be a space-separated list of urls.
+  #
+  # Example:
+  #
+  #   CSS: style.css math.css
+  #
+  #=end
+
+  # Render to a complete HTML document (returns an HTMLElement document tree)
+  def to_html_document_tree
+    root = xelem('html')
+    root['xmlns'] = 'http://www.w3.org/1999/xhtml'
+    root['xmlns:svg'] = "http://www.w3.org/2000/svg"
+    root['xml:lang'] = self.attributes[:lang] || 'en'
+
+    root << xml_newline
+    head = xelem('head')
+    root << head
+
+    #<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+    me = xelem('meta')
+    me['http-equiv'] = 'Content-type'
+    me['content'] = 'application/xhtml+xml;charset=utf-8'
+    head << me
+
+    %w(description keywords author revised).each do |m|
+      if value = self.attributes[m.to_sym]
+        meta = xelem('meta')
+        meta['name'] = m
+        meta['content'] = value.to_s
+        head << meta
+      end
+    end
+
+    self.attributes.each do |k,v|
+      if k.to_s =~ /\Ameta-(.*)\z/
+        meta = xelem('meta')
+        meta['name'] = $1
+        meta['content'] = v.to_s
+        head << meta
+      end
+    end
+
+    # Create title element
+    doc_title = self.attributes[:title] || self.attributes[:subject] || ""
+    begin
+      title_content = MaRuKu::HTMLFragment.new(doc_title).to_html
+    rescue
+      title_content = xtext(doc_title)
+    end
+    title = xelem('title') << title_content
+    head << title
+    add_css_to(head)
+
+    root << xml_newline
+
+    body = xelem('body')
+
+    children_to_html.each do |e|
+      body << e.to_s
+    end
+
+    # render footnotes
+    unless @doc.footnotes_order.empty?
+      body << render_footnotes(@doc)
+    end
+
+    # When we are rendering a whole document, we add a signature
+    # at the bottom.
+    if get_setting(:maruku_signature)
+      body << maruku_html_signature
+    end
+
+    root << body
+  end
+
+  def add_css_to(head)
+    if css_list = self.attributes[:css]
+      css_list.split.each do |css|
+        # <link type="text/css" rel="stylesheet" href="..." />
+        link = xelem('link')
+        link['type'] = 'text/css'
+        link['rel'] = 'stylesheet'
+        link['href'] = css
+        head << link << xml_newline
+      end
+    end
+  end
+
+  # returns "st","nd","rd" or "th" as appropriate
+  def day_suffix(day)
+    s = {
+      1 => 'st',
+      2 => 'nd',
+      3 => 'rd',
+      21 => 'st',
+      22 => 'nd',
+      23 => 'rd',
+      31 => 'st'
+    }
+    s[day] || 'th';
+  end
+
+  # formats a nice date
+  def nice_date
+    Time.now.strftime(" at %H:%M on %A, %B %d") +
+      day_suffix(t.day) +
+      t.strftime(", %Y")
+  end
+
+  def maruku_html_signature
+    div = xelem('div')
+    div['class'] = 'maruku_signature'
+    div << xelem('hr')
+    span = xelem('span')
+    span['style'] = 'font-size: small; font-style: italic'
+    div << span << xtext('Created by ')
+    a = xelem('a')
+    a['href'] = MaRuKu::MARUKU_URL
+    a['title'] = 'Maruku: a Markdown-superset interpreter for Ruby'
+    a << xtext('Maruku')
+    span << xtext(nice_date + ".")
+    div
+  end
+
+  def render_footnotes
+    div = xelem('div')
+    div['class'] = 'footnotes'
+    div << xelem('hr')
+    ol = xelem('ol')
+
+    @doc.footnotes_order.each_with_index do |fid, i|
+      num = i + 1
+      if f = self.footnotes[fid]
+        li = f.wrap_as_element('li')
+        li['id'] = "#{get_setting(:doc_prefix)}fn:#{num}"
+
+        a = xelem('a')
+        a['href'] = "\##{get_setting(:doc_prefix)}fnref:#{num}"
+        a['rev'] = 'footnote'
+        a << xtext([8617].pack('U*'))
+
+        last = nil
+        li.children.reverse_each do |child|
+          if child.is_a?(HTMLElement)
+            last = child
+            break
+          end
+        end
+
+        if last && last.name == "p"
+          last << xtext(' ') << a
+        else
+          li.children << a
+        end
+        ol << li
+      else
+        maruku_error "Could not find footnote id '#{fid}' among [#{self.footnotes.keys.inspect}]."
+      end
+    end
+
+    div << ol
+  end
+
+  def to_html_hrule
+    xelem('hr')
+  end
+
+  def to_html_linebreak
+    xelem('br')
+  end
+
+  # renders children as html and wraps into an element of given name
+  #
+  # Sets 'id' if meta is set
+  def wrap_as_element(name, attributes={})
+    html_element name, children_to_html, attributes
+  end
+
+  #=begin maruku_doc
+  # Attribute: id
+  # Scope: element
+  # Output: LaTeX, HTML
+  #
+  # It is copied as a standard HTML attribute.
+  #
+  # Moreover, it used as a label name for hyperlinks in both HTML and
+  # in PDF.
+  #=end
+
+  #=begin maruku_doc
+  # Attribute: class
+  # Scope: element
+  # Output: HTML
+  #
+  # It is copied as a standard HTML attribute.
+  #=end
+
+  #=begin maruku_doc
+  # Attribute: style
+  # Scope: element
+  # Output: HTML
+  #
+  # It is copied as a standard HTML attribute.
+  #=end
+
+  HTML4Attributes = {}
+
+  coreattrs = [:id, :class, :style, :title, :accesskey, :contenteditable, :dir,
+               :draggable, :spellcheck, :tabindex]
+  i18n = [:lang, :'xml:lang']
+  events = [:onclick, :ondblclick, :onmousedown, :onmouseup, :onmouseover,
+            :onmousemove, :onmouseout,
+            :onkeypress, :onkeydown, :onkeyup]
+  common_attrs = coreattrs + i18n + events
+  cells = [:align, :char, :charoff, :valign]
+
+  # Each row maps a list of tags to the list of attributes beyond the common_attributes
+  # that are valid on those elements
+  [
+   ['body', [:onload, :onunload]],
+   ['a', [:charset, :type, :name, :rel, :rev, :accesskey, :shape, :coords, :tabindex,
+          :onfocus,:onblur]],
+   ['img', [:longdesc, :name, :height, :width, :alt]],
+   ['ol', [:reversed, :start]],
+   ['li', [:value]],
+   ['table', [:summary, :width, :frame, :rules, :border, :cellspacing, :cellpadding]],
+   [%w(q blockquote), [:cite]],
+   [%w(ins del), [:cite, :datetime]],
+   [%w(colgroup col), [:span, :width] + cells],
+   [%w(thead tbody tfoot), cells],
+   [%w(td td th), [:abbr, :axis, :headers, :scope, :rowspan, :colspan] + cells],
+   [%w(em code strong hr span dl dd dt address div p pre caption ul h1 h2 h3 h4 h5 h6), []]
+  ].each do |elements, attributes|
+    [*elements].each do |element|
+      HTML4Attributes[element] = common_attrs + attributes
+    end
+  end
+
+  # Pretty much the same as the HTMLElement constructor except it
+  # copies standard attributes out of the Maruku Element's attributes hash.
+  def html_element(name, content="", attributes={})
+    attributes = content if attributes.empty? && content.is_a?(Hash)
+
+    Array(HTML4Attributes[name]).each do |att|
+      if v = @attributes[att]
+        attributes[att.to_s] = MaRuKu::Out::HTML.escapeHTML(v.to_s)
+      end
+    end
+
+    content = yield if block_given?
+
+    HTMLElement.new(name, attributes, content)
+  end
+
+  def to_html_ul
+    if @attributes[:toc]
+      # render toc
+      @doc.toc.to_html
+    else
+      add_ws wrap_as_element('ul')
+    end
+  end
+
+  def to_html_paragraph
+    add_ws wrap_as_element('p')
+  end
+
+  def to_html_ol
+    add_ws wrap_as_element('ol')
+  end
+
+  def to_html_li
+    add_ws wrap_as_element('li')
+  end
+
+  def to_html_quote
+    add_ws wrap_as_element('blockquote')
+  end
+
+  def to_html_strong
+    wrap_as_element('strong')
+  end
+
+  def to_html_emphasis
+    wrap_as_element('em')
+  end
+
+  #=begin maruku_doc
+  # Attribute: use_numbered_headers
+  # Scope: document
+  # Summary: Activates the numbering of headers.
+  #
+  # If `true`, section headers will be numbered.
+  #
+  # In LaTeX export, the numbering of headers is managed
+  # by Maruku, to have the same results in both HTML and LaTeX.
+  #=end
+
+  # nil if not applicable, else string
+  def section_number
+    return nil unless get_setting(:use_numbered_headers)
+
+    n = Array(@attributes[:section_number])
+    return nil if n.empty?
+
+    n.join('.') + ". "
+  end
+
+  # nil if not applicable, else SPAN element
+  def render_section_number
+    return nil unless section_number && !section_number.empty?
+
+    # if we are bound to a section, add section number
+    span = xelem('span')
+    span['class'] = 'maruku_section_number'
+    span << xtext(section_number)
+  end
+
+  def to_html_header
+    element_name = "h#{self.level}"
+    h = wrap_as_element element_name
+
+    if span = render_section_number
+      h.children.unshift(span)
+    end
+
+    add_ws h
+  end
+
+  #=begin maruku_doc
+  # Attribute: html_use_syntax
+  # Scope: global, document, element
+  # Output: HTML
+  # Summary: Enables the use of the `syntax` package.
+  # Related: lang, code_lang
+  # Default: <?mrk md_code(Globals[:html_use_syntax].to_s) ?>
+  #
+  # If true, the `syntax` package is used. It supports the `ruby` and `xml`
+  # languages. Remember to set the `lang` attribute of the code block.
+  #
+  # Examples:
+  #
+  #     require 'maruku'
+  #   {:lang=ruby html_use_syntax=true}
+  #
+  # and
+  #
+  #     <div style="text-align:center">Div</div>
+  #   {:lang=html html_use_syntax=true}
+  #
+  # produces:
+  #
+  #   require 'maruku'
+  # {:lang=ruby html_use_syntax=true}
+  #
+  # and
+  #
+  #   <div style="text-align:center">Div</div>
+  # {:lang=html html_use_syntax=true}
+  #
+  #=end
+
+  $syntax_loaded = false
+  def to_html_code
+    source = self.raw_code
+
+    code_lang = self.lang || self.attributes[:lang] || @doc.attributes[:code_lang]
+
+    code_lang = 'xml' if code_lang == 'html'
+    code_lang = 'css21' if code_lang == 'css'
+
+    use_syntax = get_setting :html_use_syntax
+
+    element =
+      if use_syntax && code_lang
+        begin
+          unless $syntax_loaded
+            require 'rubygems'
+            require 'syntax'
+            require 'syntax/convertors/html'
+            $syntax_loaded = true
+          end
+          convertor = Syntax::Convertors::HTML.for_syntax code_lang
+
+          # eliminate trailing newlines otherwise Syntax crashes
+          source = source.sub(/\n*\z/, '')
+
+          html = convertor.convert(source)
+
+          html.gsub!(/\'|'/,''') # IE bug
+
+          d = MaRuKu::HTMLFragment.new(html)
+          highlighted = d.to_html.sub(/\A<pre>(.*)<\/pre>\z/m, '\1')
+          code = HTMLElement.new('code', { :class => code_lang }, highlighted)
+
+          pre = xelem('pre')
+          # add a class here, too, for compatibility with existing implementations
+          pre['class'] = code_lang
+          pre << code
+          pre
+        rescue LoadError => e
+          maruku_error "Could not load package 'syntax'.\n" +
+            "Please install it, for example using 'gem install syntax'."
+          to_html_code_using_pre(source, code_lang)
+        rescue => e
+          maruku_error "Error while using the syntax library for code:\n#{source.inspect}" +
+            "Lang is #{code_lang} object is: \n" +
+            self.inspect +
+            "\nException: #{e.class}: #{e.message}"
+
+          tell_user("Using normal PRE because the syntax library did not work.")
+          to_html_code_using_pre(source, code_lang)
+        end
+      else
+        to_html_code_using_pre(source, code_lang)
+      end
+
+    color = get_setting(:code_background_color)
+    if color != MaRuKu::Globals[:code_background_color]
+      element['style'] = "background-color: #{color};"
+    end
+
+    add_ws element
+  end
+
+  #=begin maruku_doc
+  # Attribute: code_background_color
+  # Scope: global, document, element
+  # Summary: Background color for code blocks.
+  #
+  # The format is either a named color (`green`, `red`) or a CSS color
+  # of the form `#ff00ff`.
+  #
+  # * for **HTML output**, the value is put straight in the `background-color` CSS
+  #   property of the block.
+  #
+  # * for **LaTeX output**, if it is a named color, it must be a color accepted
+  #   by the LaTeX `color` packages. If it is of the form `#ff00ff`, Maruku
+  #   defines a color using the `\color[rgb]{r,g,b}` macro.
+  #
+  #   For example, for `#0000ff`, the macro is called as: `\color[rgb]{0,0,1}`.
+  #=end
+
+
+  def to_html_code_using_pre(source, code_lang=nil)
+    code = xelem('code')
+    pre = xelem('pre')
+    pre << code
+
+    if get_setting(:code_show_spaces)
+      # 187 = raquo
+      # 160 = nbsp
+      # 172 = not
+      source = source.gsub(/\t/,'»' + ' ' * 3).gsub(/ /,'¬')
+    end
+
+    code << xtext(source)
+
+    code_lang ||= self.attributes[:lang]
+    if code_lang
+      pre['class'] = code['class'] = code_lang
+    end
+
+    pre
+  end
+
+  def to_html_inline_code
+    code_attrs = {}
+    source = xtext(self.raw_code)
+
+    color = get_setting(:code_background_color)
+    if color != MaRuKu::Globals[:code_background_color]
+      code_attrs['style'] = "background-color: #{color};" + (code_attrs['style'] || "")
+    end
+
+    html_element('code', source, code_attrs)
+  end
+
+  def add_class_to(el, cl)
+    el['class'] =
+      if already = el['class']
+        already + " " + cl
+      else
+        cl
+      end
+  end
+
+  def to_html_immediate_link
+    text = self.url.gsub(/^mailto:/, '') # don't show mailto
+    html_element('a', text, 'href' => self.url)
+  end
+
+  def to_html_link
+    a = {}
+    id = self.ref_id || children_to_s
+
+    if ref = @doc.refs[sanitize_ref_id(id)] || @doc.refs[sanitize_ref_id(children_to_s)]
+      a['href'] = ref[:url] if ref[:url]
+      a['title'] = ref[:title] if ref[:title]
+    else
+      maruku_error "Could not find ref_id = #{id.inspect} for #{self.inspect}\n" +
+        "Available refs are #{@doc.refs.keys.inspect}"
+      tell_user "Not creating a link for ref_id = #{id.inspect}.\n"
+      if (self.ref_id)
+        return "[#{children_to_s}][#{id}]"
+      else
+        return "[#{children_to_s}]"
+      end
+    end
+
+    wrap_as_element('a', a)
+  end
+
+  def to_html_im_link
+    if self.url
+      a = {}
+      a['href'] = self.url
+      a['title'] = self.title if self.title
+      wrap_as_element('a', a)
+    else
+      maruku_error "Could not find url in #{self.inspect}"
+      tell_user "Not creating a link for ref_id = #{id.inspect}."
+      wrap_as_element('span')
+    end
+  end
+
+  def add_ws(e)
+    [xml_newline, e, xml_newline]
+  end
+
+  ##### Email address
+
+  def obfuscate(s)
+    s.bytes.inject('') do |res, char|
+      res << "&#%03d;" % char
+    end
+  end
+
+  def to_html_email_address
+    obfuscated = obfuscate(self.email)
+    html_element('a', obfuscated, :href => "mailto:#{obfuscated}")
+  end
+
+  ##### Images
+
+  def to_html_image
+    a = {}
+    id = self.ref_id
+    if ref = @doc.refs[sanitize_ref_id(id)] || @doc.refs[sanitize_ref_id(children_to_s)]
+      a['src'] = ref[:url].to_s
+      a['alt'] = children_to_s
+      a['title'] = ref[:title].to_s if ref[:title]
+      html_element('img', nil, a)
+    else
+      maruku_error "Could not find id = #{id.inspect} for\n #{self.inspect}"
+      tell_user "Could not create image with ref_id = #{id.inspect};" +
+        " Using SPAN element as replacement."
+      wrap_as_element('span')
+    end
+  end
+
+  def to_html_im_image
+    if self.url
+      attrs = {}
+      attrs['src'] = self.url.to_s
+      attrs['alt'] = children_to_s
+      attrs['title'] = self.title.to_s if self.title
+      html_element('img', nil, attrs)
+    else
+      maruku_error "Image with no url: #{self.inspect}"
+      tell_user "Could not create image without a source URL;" +
+        " Using SPAN element as replacement."
+      wrap_as_element('span')
+    end
+  end
+
+  #=begin maruku_doc
+  # Attribute: filter_html
+  # Scope: document
+  #
+  # If true, raw HTML is discarded from the output.
+  #
+  #=end
+
+  def to_html_raw_html
+    return [] if get_setting(:filter_html)
+    return parsed_html.to_html if parsed_html
+
+    # If there's no parsed HTML
+    raw_html = self.raw_html
+
+    # Creates red box with offending HTML
+    tell_user "Wrapping bad html in a PRE with class 'markdown-html-error'\n" +
+      raw_html.gsub(/^/, '|')
+    pre = xelem('pre')
+    pre['style'] = 'border: solid 3px red; background-color: pink'
+    pre['class'] = 'markdown-html-error'
+    pre << xtext("Maruku could not parse this XML/HTML: \n#{raw_html}")
+  end
+
+  def to_html_abbr
+    abbr = xelem('abbr')
+    abbr << xtext(children[0])
+    abbr['title'] = self.title if self.title
+    abbr
+  end
+
+  def to_html_footnote_reference
+    id = self.footnote_id
+
+    # save the order of used footnotes
+    order = @doc.footnotes_order
+
+    # footnote has already been used
+    return [] if order.include?(id)
+
+    return [] unless @doc.footnotes[id]
+
+    # take next number
+    order << id
+
+    num = order.index(id) + 1
+
+    sup = xelem('sup')
+    sup['id'] = "#{get_setting(:doc_prefix)}fnref:#{num}"
+    a = xelem('a')
+    a << xtext(num.to_s)
+    a['href'] = "\##{get_setting(:doc_prefix)}fn:#{num}"
+    a['rel'] = 'footnote'
+    sup << a
+  end
+
+  ## Definition lists ###
+  def to_html_definition_list
+    add_ws wrap_as_element('dl')
+  end
+
+  def to_html_definition
+    children_to_html
+  end
+
+  def to_html_definition_term
+    add_ws wrap_as_element('dt')
+  end
+
+  def to_html_definition_data
+    add_ws wrap_as_element('dd')
+  end
+
+  def to_html_table
+    num_columns = self.align.size
+
+    # The table data is passed as a multi-dimensional array
+    # we just need to split the head from the body
+    head, *rows = @children
+
+    table = html_element('table')
+    thead = xelem('thead')
+    tr = xelem('tr')
+    array_to_html(head).inject(tr, &:<<)
+    thead << tr
+    table << thead
+
+    tbody = xelem('tbody')
+    rows.each do |row|
+      tr = xelem('tr')
+      array_to_html(row).each_with_index do |x, i|
+        x['style'] ="text-align: #{self.align[i].to_s};"
+        tr << x
+      end
+
+      tbody << tr << xml_newline
+    end
+
+    table << tbody
+  end
+
+  def to_html_head_cell
+    wrap_as_element('th')
+  end
+
+  def to_html_cell
+    if @attributes[:scope]
+      wrap_as_element('th')
+    else
+      wrap_as_element('td')
+    end
+  end
+
+  def to_html_entity
+    entity_name = self.entity_name
+
+    if entity = MaRuKu::Out::EntityTable.instance.entity(entity_name)
+      entity_name = entity.html_num
+    end
+
+    if entity_name.kind_of? Fixnum
+      # Convert numeric entities to unicode characters
+      xtext([entity_name].pack('U*'))
+    else
+      "&#{entity_name};"
+    end
+  end
+
+  def to_html_xml_instr
+    target = self.target || ''
+    code = self.code || ''
+
+    # A blank target is invalid XML. Just create a text node?
+    if target.empty?
+      xtext("<?#{code}?>")
+    else
+      "<?#{target} #{code}?>"
+    end
+  end
+
+  # Convert each child to html
+  def children_to_html
+    array_to_html(@children)
+  end
+
+  def array_to_html(array)
+    e = []
+    array.each do |c|
+      if c.kind_of?(String)
+        e << xtext(c)
+      else
+        if c.kind_of?(HTMLElement)
+          e << c
+          next
+        end
+
+        method = c.kind_of?(MaRuKu::MDElement) ? "to_html_#{c.node_type}" : "to_html"
+        next unless c.respond_to?(method)
+
+        h = c.send(method)
+
+        unless h
+          raise "Nil html created by method  #{method}:\n#{h.inspect}\n" +
+            " for object #{c.inspect[0,300]}"
+        end
+
+        if h.kind_of? Array
+          e.concat h
+        else
+          e << h
+        end
+      end
+    end
+    e
+  end
+
+  def to_html_ref_definition
+    []
+  end
+
+  def to_latex_ref_definition
+    []
+  end
+end
diff --git a/lib/maruku/output/to_latex.rb b/lib/maruku/output/to_latex.rb
index 8379b88..cf282cf 100644
--- a/lib/maruku/output/to_latex.rb
+++ b/lib/maruku/output/to_latex.rb
@@ -1,121 +1,107 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
+require 'set'
 
-module MaRuKu
+module MaRuKu::Out::Latex
+  module MDDocumentExtensions
+    # @return [Set<String>]
+    attr_accessor :latex_required_packages
+
+    def latex_require_package(p)
+      self.latex_required_packages << p
+    end
 
-class MDDocument
+    def initialize(*args)
+      self.latex_required_packages = Set.new
+      super
+    end
+  end
 
-	Latex_preamble_enc_cjk = 
-"\\usepackage[C40]{fontenc}
+  Latex_preamble_enc_cjk =
+    "\\usepackage[C40]{fontenc}
 \\usepackage[cjkjis]{ucs}
 \\usepackage[utf8x]{inputenc}"
 
-	Latex_preamble_enc_utf8 = 
-"\\usepackage{ucs}
+  Latex_preamble_enc_utf8 =
+    "\\usepackage{ucs}
 \\usepackage[utf8x]{inputenc}"
 
-	def latex_require_package(p)
-		if not self.latex_required_packages.include? p
-			self.latex_required_packages.push p
-		end
-	end
-
-	# Render as a LaTeX fragment 
-	def to_latex
-		children_to_latex
-	end
-
-=begin maruku_doc
-Attribute: maruku_signature
-Scope: document
-Output: html, latex
-Summary: Enables Maruku's signature.
-Default: true
-
-If false, Maruku does not append a signature to the
-generated file.
-=end
-
-	# Render as a complete LaTeX document 
-	def to_latex_document
-		body = to_latex
-		
-		if get_setting(:maruku_signature)
-			body += render_latex_signature 
-		end
-		
-		required = 
-		self.latex_required_packages.map {|p|
-			"\\usepackage{#{p}}\n"
-		}.join
-		
-=begin maruku_doc
-Attribute: latex_cjk
-Scope:     document
-Output:    latex
-Summary:   Support for CJK characters.
-
-If the `latex_cjk` attribute is specified, then appropriate headers
-are added to the LaTeX preamble to support Japanese fonts.
-You have to have these fonts installed -- and this can be a pain.
-
-If `latex_cjk` is specified, this is added to the preamble:
-
-<?mrk puts "ciao" ?> 
-
-<?mrk md_codeblock(Maruku::MDDocument::Latex_preamble_enc_cjk) ?>
-
-
-while the default is to add this:
-
-<?mrk md_codeblock(Maruku::MDDocument::Latex_preamble_enc_utf8) ?>
-
-=end
-		encoding = get_setting(:latex_cjk) ? 
-			Latex_preamble_enc_cjk : Latex_preamble_enc_utf8
-
-=begin maruku_doc
-Attribute: latex_preamble
-Scope:     document
-Output:    latex
-Summary:   User-defined preamble.
-
-If the `latex_preamble` attribute is specified, then its value
-will be used as a custom preamble. 
-
-For example:
-
-	Title: My document
-	Latex preamble: preamble.tex
-
-will produce:
-
-	...
-	\input{preamble.tex}
-	...
-
-=end
-	user_preamble = (file = @doc.attributes[:latex_preamble]) ?
-		"\\input{#{file}}\n" : ""
-		
-"\\documentclass{article}
+  # Render as a LaTeX fragment
+  def to_latex
+    children_to_latex
+  end
+
+  #=begin maruku_doc
+  # Attribute: maruku_signature
+  # Scope: document
+  # Output: html, latex
+  # Summary: Enables Maruku's signature.
+  # Default: true
+  #
+  # If false, Maruku does not append a signature to the
+  # generated file.
+  #=end
+
+  # Render as a complete LaTeX document
+  def to_latex_document
+    body = to_latex
+
+    if get_setting(:maruku_signature)
+      body << render_latex_signature
+    end
+
+    required = self.latex_required_packages.map do |p|
+      "\\usepackage{#{p}}\n"
+    end.join
+
+    #=begin maruku_doc
+    # Attribute: latex_cjk
+    # Scope:     document
+    # Output:    latex
+    # Summary:   Support for CJK characters.
+    #
+    # If the `latex_cjk` attribute is specified, then appropriate headers
+    # are added to the LaTeX preamble to support Japanese fonts.
+    # You have to have these fonts installed -- and this can be a pain.
+    #
+    # If `latex_cjk` is specified, this is added to the preamble:
+    #
+    # <?mrk puts "ciao" ?>
+    #
+    # <?mrk md_codeblock(Maruku::MDDocument::Latex_preamble_enc_cjk) ?>
+    #
+    #
+    # while the default is to add this:
+    #
+    # <?mrk md_codeblock(Maruku::MDDocument::Latex_preamble_enc_utf8) ?>
+    #
+    #=end
+
+    encoding = get_setting(:latex_cjk) ? Latex_preamble_enc_cjk : Latex_preamble_enc_utf8
+
+    #=begin maruku_doc
+    # Attribute: latex_preamble
+    # Scope:     document
+    # Output:    latex
+    # Summary:   User-defined preamble.
+    #
+    # If the `latex_preamble` attribute is specified, then its value
+    # will be used as a custom preamble.
+    #
+    # For example:
+    #
+    #   Title: My document
+    #   Latex preamble: preamble.tex
+    #
+    # will produce:
+    #
+    #   ...
+    #   \input{preamble.tex}
+    #   ...
+    #
+    #=end
+
+    user_preamble = (file = @doc.attributes[:latex_preamble]) ? "\\input{#{file}}\n" : ""
+
+    "\\documentclass{article}
 
 % Packages required to support encoding
 #{encoding}
@@ -131,460 +117,481 @@ will produce:
 
 #{user_preamble}
 
-\\begin{document} 
+\\begin{document}
 #{body}
 \\end{document}
-"	
-	end
-	
-	
-	def render_latex_signature
-"\\vfill
+"
+  end
+
+  def render_latex_signature
+    "\\vfill
 \\hrule
 \\vspace{1.2mm}
 \\begin{tiny}
-Created by \\href{http://maruku.rubyforge.org}{Maruku} #{self.nice_date}.
+Created by \\href{#{MaRuKu::MARUKU_URL}}{Maruku} #{self.nice_date}.
 \\end{tiny}"
-	end
-
-end end
-
-module MaRuKu; module Out; module Latex
-	
-	def to_latex_hrule; "\n\\vspace{.5em} \\hrule \\vspace{.5em}\n" end
-	def to_latex_linebreak; "\\newline " end
-	
-	def to_latex_paragraph 
-		children_to_latex+"\n\n"
-	end
-
-	
-=begin maruku_doc
-Title: Input format for colors
-Output: latex, html
-Related: code_background_color
-
-Admissible formats:
-
-	green
-	#abc
-	#aabbcc
-=end
-
-	# \color[named]{name} 	
-	# \color[rgb]{1,0.2,0.3} 
-	def latex_color(s, command='color')
-		if s =~ /^\#(\w\w)(\w\w)(\w\w)$/
-			r = $1.hex; g = $2.hex; b=$3.hex
-			# convert from 0-255 to 0.0-1.0
-			r = r / 255.0; g = g / 255.0; b = b / 255.0; 
-			"\\#{command}[rgb]{%0.2f,%0.2f,%0.2f}" % [r,g,b]
-		elsif s =~ /^\#(\w)(\w)(\w)$/
-			r = $1.hex; g = $2.hex; b=$3.hex
-			# convert from 0-15 to 0.0-1.0
-			r = r / 15.0; g = g / 15.0; b = b / 15.0; 
-			"\\#{command}[rgb]{%0.2f,%0.2f,%0.2f}" % [r,g,b]
-		else	
-			"\\#{command}{#{s}}"
-		end
-	end
-	
-=begin maruku_doc
-Attribute: code_show_spaces
-Scope: global, document, element
-
-If `true`, shows spaces and tabs in code blocks.
-
-Example:
-
-		 One space
-		  Two spaces
-			 	Tab, space, tab
-					Tab, tab, tab and all is green!
-	{:code_show_spaces code_background_color=#ffeedd}
-{:markdown}
-	
-That will produce:
-
-	 One space
-	  Two spaces
-		 	Tab, space, tab
-				Tab, tab, tab and all is green!
-{:code_show_spaces code_background_color=#ffeedd}
-
-=end
-	
-=begin maruku_doc
-Attribute: latex_use_listings
-Scope: document
-Output: latex
-Summary: Support for `listings` package.
-Related: code_show_spaces, code_background_color, lang, code_lang
-
-If the `latex_use_listings` attribute is specified, then 
-code block are rendered using the `listings` package.
-Otherwise, a standard `verbatim` environment is used.
-
-*	If the `lang` attribute for the code block has been specified,
-	it gets passed to the `listings` package using the `lstset` macro.
-	The default lang for code blocks is specified through 
-	the `code_lang` attribute.
-
-		\lstset{language=ruby}
-
-	Please refer to the documentation of the `listings` package for
-	supported languages.
-
-	If a language is not supported, the `listings` package will emit
-	a warning during the compilation. Just press enter and nothing
-	wrong will happen.
-
-*	If the `code_show_spaces` is specified, than spaces and tabs will
-	be shown using the macro:
-
-		\lstset{showspaces=true,showtabs=true}
-
-*	The background color is given by `code_background_color`.
-
-=end
-
-	def to_latex_code;
-		raw_code = self.raw_code
-		
-		if get_setting(:latex_use_listings)
-			@doc.latex_require_package('listings')
-				
-			s = "\\lstset{columns=fixed,frame=shadowbox}"
-
-			if get_setting(:code_show_spaces) 
-				s+= "\\lstset{showspaces=true,showtabs=true}\n"
-			else
-				s+= "\\lstset{showspaces=false,showtabs=false}\n"
-			end
-			
-			color = latex_color get_setting(:code_background_color)
-			
-			s+= "\\lstset{backgroundcolor=#{color}}\n" 
-			
-			s+= "\\lstset{basicstyle=\\ttfamily\\footnotesize}\n" 
-			
-			
-			lang = self.attributes[:lang] || @doc.attributes[:code_lang] || '{}'
-			if lang
-				s += "\\lstset{language=#{lang}}\n"
-			end
-			
-			"#{s}\n\\begin{lstlisting}\n#{raw_code}\n\\end{lstlisting}"
-		else
-			"\\begin{verbatim}#{raw_code}\\end{verbatim}\n"
-		end
-	end
-	
-	TexHeaders = {
-		1=>'section',
-		2=>'subsection',
-		3=>'subsubsection',
-		4=>'paragraph'}
-
-	def to_latex_header
-		h = TexHeaders[self.level] || 'paragraph'
-		
-		title = children_to_latex
-		if number = section_number
-			title = number + title
-		end
-		
-		if id = self.attributes[:id]
-			# drop '#' at the beginning
-			if id[0,1] == '#' then id = [1,id.size] end
-			%{\\hypertarget{%s}{}\\%s*{{%s}}\\label{%s}\n\n} % [ id, h, title, id ]
-		else
-			%{\\%s*{%s}\n\n} % [ h, title]
-		end
-	end
-	
-	
-	def to_latex_ul;       
-		if self.attributes[:toc]
-			@doc.toc.to_latex
-		else
-			wrap_as_environment('itemize')
-		end
-	end
-		   
-	def to_latex_quote;        wrap_as_environment('quote')               end
-	def to_latex_ol;        wrap_as_environment('enumerate')               end
-	def to_latex_li;        
-		"\\item #{children_to_latex}\n"  
-	end
-	def to_latex_li_span;
-		"\\item #{children_to_latex}\n"
-	end
-
-	def to_latex_strong
-		"\\textbf{#{children_to_latex}}"
- 	end
-	def to_latex_emphasis
-		"\\emph{#{children_to_latex}}"
-	end
-	
-	def wrap_as_span(c)
-		"{#{c} #{children_to_latex}}"
-	end
-	
-	def wrap_as_environment(name)
-"\\begin{#{name}}%
+  end
+
+  def to_latex_hrule
+    "\n\\vspace{.5em} \\hrule \\vspace{.5em}\n"
+  end
+
+  def to_latex_linebreak
+    "\\newline "
+  end
+
+  def to_latex_paragraph
+    children_to_latex + "\n\n"
+  end
+
+  #=begin maruku_doc
+  # Title: Input format for colors
+  # Output: latex, html
+  # Related: code_background_color
+  #
+  # Admissible formats:
+  #
+  #   green
+  #   #abc
+  #   #aabbcc
+  #=end
+
+  # \color{name}
+  # \color[rgb]{1,0.2,0.3}
+  def latex_color(s, command='color')
+    if s =~ /\A\#([1-9A-F]{1,2})([1-9A-F]{1,2})([1-9A-F]{1,2})\z/i
+      # convert from 0-255 or 0-15 to 0.0-1.0
+      r, g, b = [$1, $2, $3].map {|c| c.hex / (c.length == 1 ? 15.0 : 255.0) }
+      "\\#{command}[rgb]{%0.2f,%0.2f,%0.2f}" % [r, g, b]
+    else
+      "\\#{command}{#{s}}"
+    end
+  end
+
+  #=begin maruku_doc
+  # Attribute: code_show_spaces
+  # Scope: global, document, element
+  #
+  # If `true`, shows spaces and tabs in code blocks.
+  #
+  # Example:
+  #
+  #      One space
+  #       Two spaces
+  #         Tab, space, tab
+  #           Tab, tab, tab and all is green!
+  #   {:code_show_spaces code_background_color=#ffeedd}
+  # {:markdown}
+  #
+  # That will produce:
+  #
+  #    One space
+  #     Two spaces
+  #       Tab, space, tab
+  #         Tab, tab, tab and all is green!
+  # {:code_show_spaces code_background_color=#ffeedd}
+  #
+  #=end
+
+  #=begin maruku_doc
+  # Attribute: latex_use_listings
+  # Scope: document
+  # Output: latex
+  # Summary: Support for `listings` package.
+  # Related: code_show_spaces, code_background_color, lang, code_lang
+  #
+  # If the `latex_use_listings` attribute is specified, then
+  # code block are rendered using the `listings` package.
+  # Otherwise, a standard `verbatim` environment is used.
+  #
+  # * If the `lang` attribute for the code block has been specified,
+  #   it gets passed to the `listings` package using the `lstset` macro.
+  #   The default lang for code blocks is specified through
+  #   the `code_lang` attribute.
+  #
+  #     \lstset{language=ruby}
+  #
+  #   Please refer to the documentation of the `listings` package for
+  #   supported languages.
+  #
+  #   If a language is not supported, the `listings` package will emit
+  #   a warning during the compilation. Just press enter and nothing
+  #   wrong will happen.
+  #
+  # * If the `code_show_spaces` is specified, than spaces and tabs will
+  #   be shown using the macro:
+  #
+  #     \lstset{showspaces=true,showtabs=true}
+  #
+  # * The background color is given by `code_background_color`.
+  #
+  #=end
+
+  def to_latex_code
+    if get_setting(:latex_use_listings)
+      @doc.latex_require_package('listings')
+
+      s = "\\lstset{columns=fixed,frame=shadowbox}"
+
+      if get_setting(:code_show_spaces)
+        s << "\\lstset{showspaces=true,showtabs=true}\n"
+      else
+        s << "\\lstset{showspaces=false,showtabs=false}\n"
+      end
+
+      color = latex_color get_setting(:code_background_color)
+
+      s << "\\lstset{backgroundcolor=#{color}}\n"
+
+      s << "\\lstset{basicstyle=\\ttfamily\\footnotesize}\n"
+
+
+      lang = self.attributes[:lang] || @doc.attributes[:code_lang] || '{}'
+      s << "\\lstset{language=#{lang}}\n" if lang
+
+      "#{s}\n\\begin{lstlisting}\n#{self.raw_code}\n\\end{lstlisting}"
+    else
+      "\\begin{verbatim}#{self.raw_code}\\end{verbatim}\n"
+    end
+  end
+
+  def to_latex_header
+    header_levels = %w(section subsection subsubsection)
+    h = header_levels[self.level - 1] || 'paragraph'
+
+    title = children_to_latex
+    if number = section_number
+      title = number + title
+    end
+
+    if id = self.attributes[:id]
+      # drop '#' at the beginning
+      id = id[1..-1] if id.start_with? '#'
+      %{\\hypertarget{%s}{}\\%s*{{%s}}\\label{%s}\n\n} % [ id, h, title, id ]
+    else
+      %{\\%s*{%s}\n\n} % [ h, title]
+    end
+  end
+
+  def to_latex_ul
+    if self.attributes[:toc]
+      @doc.toc.to_latex
+    else
+      wrap_as_environment('itemize')
+    end
+  end
+
+  def to_latex_quote
+    wrap_as_environment('quote')
+  end
+
+  def to_latex_ol
+    wrap_as_environment('enumerate')
+  end
+
+  def to_latex_li
+    "\\item #{children_to_latex}\n"
+  end
+
+  def to_latex_strong
+    "\\textbf{#{children_to_latex}}"
+  end
+
+  def to_latex_emphasis
+    "\\emph{#{children_to_latex}}"
+  end
+
+  def wrap_as_span(c)
+    "{#{c} #{children_to_latex}}"
+  end
+
+  def wrap_as_environment(name)
+    "\\begin{#{name}}%
 #{children_to_latex}
-\\end{#{name}}\n"	
-	end
-	
-	SAFE_CHARS = Set.new((?a..?z).to_a + (?A..?Z).to_a)
-	# the ultimate escaping
-	# (is much better than using \verb)
-	def latex_escape(source)
-		s=""; 
-		
-		source.each_byte do |b| 
-			if b == ?\ 
-				s << '~'
-			elsif SAFE_CHARS.include? b
-				s << b
-			else
-				s += "\\char%d" % b 
-			end
-		end
-		s
-	end
-	
-	def to_latex_inline_code; 
-		source = self.raw_code
-		
-		# Convert to printable latex chars 
-		s = latex_escape(source)
-		
-		color = get_setting(:code_background_color)
-		colorspec = latex_color(color, 'colorbox')
-
-		"{#{colorspec}{\\tt #{s}}}"
-	end
-
-	def to_latex_immediate_link
-		url = self.url
-		text = url.gsub(/^mailto:/,'') # don't show mailto
-#			gsub('~','$\sim$')
-		text = latex_escape(text)
-		if url[0,1] == '#'
-			url = url[1,url.size]
-			return "\\hyperlink{#{url}}{#{text}}"
-		else
-
-			return "\\href{#{url}}{#{text}}"
-		end
-	end
-
-	def to_latex_im_link
-		url = self.url
-
-		if url[0,1] == '#'
-			url = url[1,url.size]
-			return "\\hyperlink{#{url}}{#{children_to_latex}}"
-		else
-			return "\\href{#{url}}{#{children_to_latex}}"
-		end
-	end
-	
-	def to_latex_link
-		id = self.ref_id
-		ref = @doc.refs[id]
-		if not ref
-			$stderr.puts "Could not find id = '#{id}'"
-			return children_to_latex
-		else
-			url = ref[:url]
-			#title = ref[:title] || 'no title'
-
-			if url[0,1] == '#'
-				url = url[1,url.size]
-				return "\\hyperlink{#{url}}{#{children_to_latex}}"
-			else
-				return "\\href{#{url}}{#{children_to_latex}}"
-			end
-		end
-		
-	end
-	
-	def to_latex_email_address
-		email = self.email
-		"\\href{mailto:#{email}}{#{latex_escape(email)}}"
-	end
-	
-	
-	def to_latex_table
-		align = self.align
-		num_columns = align.size
-
-		head = @children.slice(0, num_columns)
-		rows = []
-		i = num_columns
-		while i<@children.size
-			rows << @children.slice(i, num_columns)
-			i+=num_columns
-		end
-		
-		h = {:center=>'c',:left=>'l',:right=>'r'}
-		align_string = align.map{|a| h[a]}.join('|')
-		
-		s = "\\begin{tabular}{#{align_string}}\n"
-			
-			s += array_to_latex(head, '&') + "\\\\" +"\n"
-			
-			s += "\\hline \n"
-			
-			rows.each do |row|
-				s += array_to_latex(row, '&') + "\\\\" +"\n"
-			end
-			
-		s += "\\end{tabular}"
-		
-		# puts table in its own paragraph
-		s += "\n\n"
-		
-		s
-	end
-	
-	
-	def to_latex_head_cell; children_to_latex end
-	def to_latex_cell; children_to_latex end
-	
-	
-	def to_latex_footnote_reference
-		id = self.footnote_id
-		f = @doc.footnotes[id]
-		if f
-			"\\footnote{#{f.children_to_latex.strip}} "
-		else
-			$stderr.puts "Could not find footnote '#{fid}'"
-		end
-	end
-	
-	def to_latex_raw_html
-		#'{\bf Raw HTML removed in latex version }'
-		""
-	end
-	
-	## Definition lists ###
-	def to_latex_definition_list
-		s = "\\begin{description}\n"
-		s += children_to_latex
-		s += "\\end{description}\n"
-		s
-	end
-	
-	def to_latex_definition		
-		terms = self.terms
-		definitions = self.definitions
-		
-		s = ""
-		terms.each do |t|
-			s +="\n\\item[#{t.children_to_latex}] "
-		end
-
-		definitions.each do |d|
-			s += "#{d.children_to_latex} \n"
-		end
-		
-		s
-	end
-	
-
-	def to_latex_abbr
-		children_to_latex
-	end
-
-	def to_latex_image
-		id = self.ref_id
-		ref = @doc.refs[id]
-		if not ref
-			maruku_error "Could not find ref #{id.inspect} for image.\n"+
-				"Available are: #{@docs.refs.keys.inspect}"
-#			$stderr.puts "Could not find id = '#{id}'"
-			""
-		else
-			url = ref[:url]
-			$stderr.puts "Images not supported yet (#{url})"
-			# "{\\bf Images not supported yet (#{latex_escape(url)})}"
-			""
-		end
-
-	end
-
-	def to_latex_div
-		type = self.attributes[:class]
-		id = self.attributes[:id]
-		case type
-		  when /^un_(\w*)/
-                	s = "\\begin{u#{$1}}"
-#			s += "[#{@children[0].send('children_to_latex')}]"
-			@children.delete_at(0)
-                	s += "\n" + children_to_latex
-                	s += "\\end{u#{$1}}\n"
-		  when /^num_(\w*)/
-                        s = "\\begin{#{$1}}"
-#			s += "[#{@children[0].send('children_to_latex')}]"
-			@children.delete_at(0)
-			s += "\n\\label{#{id}}\\hypertarget{#{id}}{}\n"
-                        s += children_to_latex
-                        s += "\\end{#{$1}}\n"
-                  when /^proof/
-                        s = "\\begin{proof}"
-                        @children.delete_at(0)
-                        s += "\n" + children_to_latex
-                        s += "\\end{proof}\n"
-		  else
-			s = children_to_latex
-		end
-                s
-	end
-
-	# Convert each child to html
-	def children_to_latex
-		array_to_latex(@children)
-	end
-
-	def array_to_latex(array, join_char='')
-		e = []
-		array.each do |c|
-			method = c.kind_of?(MDElement) ? 
-			   "to_latex_#{c.node_type}" : "to_latex"
-			
-			if not c.respond_to?(method)
-		#		raise "Object does not answer to #{method}: #{c.class} #{c.inspect[0,100]}"
-				next
-			end
-			
-			h =  c.send(method)
-			
-			if h.nil?
-				raise "Nil html for #{c.inspect} created with method #{method}"
-			end
-			
-			if h.kind_of?Array
-				e = e + h
-			else
-				e << h
-			end
-		end
-		
-		# puts a space after commands if needed
-		# e.each_index do |i|
-		# 	if e[i] =~ /\\\w+\s*$/ # command
-		# 		if (s=e[i+1]) && s[0] == ?\ # space
-		# 			e[i]  = e[i] + "\\ "
-		# 		end
-		# 	end
-		# end
-		
-		e.join(join_char)
-	end
-	
-end end end # MaRuKu::Out::Latex
+\\end{#{name}}\n"
+  end
+
+  SAFE_CHARS = Set.new(('a'..'z').to_a + ('A'..'Z').to_a)
+
+  # the ultimate escaping
+  # (is much better than using \verb)
+  def latex_escape(source)
+    source.chars.inject('') do |s, b|
+      s << if b == '\\'
+             '~'
+           elsif SAFE_CHARS.include? b
+             b
+           else
+             "\\char%d" % b[0].ord
+           end
+    end
+  end
+
+  def to_latex_entity
+    entity_name = self.entity_name
+
+    entity = MaRuKu::Out::EntityTable.instance.entity(entity_name)
+    unless entity
+      maruku_error "I don't know how to translate entity '#{entity_name}' to LaTeX."
+      return ""
+    end
+
+    replace = entity.latex_string
+    @doc.latex_require_package entity.latex_package if entity.latex_package
+
+    if replace
+      if replace.start_with?("\\") && !replace.end_with?('$', '}')
+        replace + "{}"
+      else
+        replace
+      end
+    else
+      tell_user "Cannot translate entity #{entity_name.inspect} to LaTeX."
+      entity_name
+    end
+  end
+
+  def to_latex_inline_code
+    # Convert to printable latex chars
+    s = latex_escape(self.raw_code)
+
+    color = get_setting(:code_background_color)
+    colorspec = latex_color(color, 'colorbox')
+
+    "{#{colorspec}{\\tt #{s}}}"
+  end
+
+  def to_latex_immediate_link
+    url = self.url
+    text = url.gsub(/^mailto:/,'') # don't show mailto
+    text = latex_escape(text)
+    if url.start_with? '#'
+      url = url[1..-1]
+      "\\hyperlink{#{url}}{#{text}}"
+    else
+      "\\href{#{url}}{#{text}}"
+    end
+  end
+
+  def to_latex_im_link
+    url = self.url
+
+    if url.start_with? '#'
+      url = url[1..-1]
+      "\\hyperlink{#{url}}{#{children_to_latex}}"
+    else
+      "\\href{#{url}}{#{children_to_latex}}"
+    end
+  end
+
+  def to_latex_link
+    id = self.ref_id || children_to_s
+    ref = @doc.refs[sanitize_ref_id(id)] || @doc.refs[sanitize_ref_id(children_to_s)]
+    if ref
+      url = ref[:url]
+
+      if url.start_with? '#'
+        url = url[1..-1]
+        "\\hyperlink{#{url}}{#{children_to_latex}}"
+      else
+        "\\href{#{url}}{#{children_to_latex}}"
+      end
+    else
+      $stderr.puts "Could not find id = '#{id}'"
+      children_to_latex
+    end
+  end
+
+  def to_latex_email_address
+    "\\href{mailto:#{self.email}}{#{latex_escape(self.email)}}"
+  end
+
+  def to_latex_table
+    num_columns = self.align.size
+
+    head, *rows = @children
+
+    h = { :center => 'c' , :left => 'l' , :right => 'r'}
+    align_string = self.align.map {|a| h[a] }.join('|')
+
+    s = "\\begin{tabular}{#{align_string}}\n"
+
+    s << array_to_latex(head, '&') + "\\\\" + "\n"
+
+    s << "\\hline \n"
+
+    rows.each do |row|
+      s << array_to_latex(row, '&') + "\\\\" + "\n"
+    end
+
+    s << "\\end{tabular}"
+
+    # puts table in its own paragraph
+    s << "\n\n"
+  end
+
+
+  def to_latex_head_cell
+    to_latex_cell
+  end
+
+  def to_latex_cell
+    s=""
+    if @attributes.has_key?(:colspan)
+      # TODO figure out how to set the alignment (defaulting to left for now)
+      s="\\multicolumn {"<< @attributes[:colspan]<<"}{|l|}{"<<children_to_latex<<"}"
+    else
+      children_to_latex
+    end
+  end
+
+  def to_latex_footnote_reference
+    id = self.footnote_id
+    if f = @doc.footnotes[id]
+      "\\footnote{#{f.children_to_latex.strip}} "
+    else
+      $stderr.puts "Could not find footnote '#{id}'"
+    end
+  end
+
+  def to_latex_raw_html
+    # Raw HTML removed in latex version
+    ""
+  end
+
+  ## Definition lists ###
+  def to_latex_definition_list
+    s = "\\begin{description}\n"
+    s << children_to_latex
+    s << "\\end{description}\n"
+  end
+
+  def to_latex_definition
+    s = ""
+
+    self.terms.each do |t|
+      s << "\n\\item[#{t.children_to_latex}] "
+    end
+
+    self.definitions.each do |d|
+      s << "#{d.children_to_latex} \n"
+    end
+
+    s
+  end
+
+  def to_latex_abbr
+    children_to_latex
+  end
+
+  def to_latex_image
+    id = self.ref_id
+    ref = @doc.refs[sanitize_ref_id(id)] || @doc.refs[sanitize_ref_id(children_to_s)]
+    if ref
+      url = ref[:url]
+      $stderr.puts "Images not supported yet (#{url})"
+      ""
+    else
+      maruku_error "Could not find ref #{id.inspect} for image.\n"+
+        "Available are: #{@docs.refs.keys.inspect}"
+      ""
+    end
+  end
+
+  def to_latex_div
+    type = self.attributes[:class]
+    id = self.attributes[:id]
+    case type
+    when /^un_(\w*)/
+      @children.shift
+      s = "\\begin{u#{$1}}\n"
+      s << children_to_latex
+      s << "\\end{u#{$1}}\n"
+    when /^num_(\w*)/
+      @children.delete_at(0)
+      s = "\\begin{#{$1}}"
+      s << "\n\\label{#{id}}\\hypertarget{#{id}}{}\n"
+      s << children_to_latex
+      s << "\\end{#{$1}}\n"
+    when /^proof/
+      @children.delete_at(0)
+      s = "\\begin{proof}\n"
+      s << children_to_latex
+      s << "\\end{proof}\n"
+    else
+      children_to_latex
+    end
+  end
+
+  # Convert each child to html
+  def children_to_latex
+    array_to_latex(@children)
+  end
+
+  def array_to_latex(array, join_char='')
+    e = []
+    array.each do |c|
+      if c.kind_of?(String)
+        e << string_to_latex(c)
+      else method = c.kind_of?(Maruku::MDElement) ? "to_latex_#{c.node_type}" : "to_latex"
+        next unless c.respond_to?(method)
+
+        h =  c.send(method)
+
+        unless h
+          raise "Nil latex for #{c.inspect} created with method #{method}"
+        end
+
+        if h.kind_of? Array
+          e.concat h
+        else
+          e << h
+        end
+      end
+    end
+    e.join(join_char)
+  end
+
+  # These are TeX's special characters
+  LATEX_ADD_SLASH = %w({ } $ & # _ %)
+
+  # These, we transform to {\tt \char<ascii code>}
+  LATEX_TO_CHARCODE = %w(^ ~ > <)
+
+  # escapes special characters
+  def string_to_latex(s)
+    s = escape_to_latex(s)
+    OtherGoodies.each do |k, v|
+      s.gsub!(k, v)
+    end
+    s
+  end
+
+  # other things that are good on the eyes
+  OtherGoodies = {
+    /(\s)LaTeX/ => '\1\\LaTeX\\xspace ', # XXX not if already \LaTeX
+  }
+
+  private
+
+  def escape_to_latex(s)
+    s.chars.inject("") do |result, b|
+      if LATEX_TO_CHARCODE.include? b
+        result << "{\\tt \\symbol{#{b[0].ord}}}"
+      elsif LATEX_ADD_SLASH.include? b
+        result << '\\' << b
+      elsif b == '\\'
+        # there is no backslash in cmr10 fonts
+        result << "$\\backslash$"
+      else
+        result << b
+      end
+    end
+  end
+end
+
+module MaRuKu
+  class MDDocument
+    include MaRuKu::Out::Latex::MDDocumentExtensions
+  end
+end
diff --git a/lib/maruku/output/to_latex_entities.rb b/lib/maruku/output/to_latex_entities.rb
deleted file mode 100644
index ae31454..0000000
--- a/lib/maruku/output/to_latex_entities.rb
+++ /dev/null
@@ -1,367 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-require 'rexml/document'
-
-module MaRuKu; module Out; module Latex
-	
-	include REXML
-	
-	def to_latex_entity 
-		MaRuKu::Out::Latex.need_entity_table
-		
-		entity_name = self.entity_name
-	
-		entity = ENTITY_TABLE[entity_name]
-		if not entity
-			maruku_error "I don't know how to translate entity '#{entity_name}' "+
-			"to LaTeX."
-			return ""
-		end
-		replace = entity.latex_string
-		
-		entity.latex_packages.each do |p|
-			@doc.latex_require_package p
-		end
-		
-#		if replace =~ /^\\/
-#			replace = replace + " "
-#		end
-		
- 		if replace
-			return replace + "{}"
-		else
-			tell_user "Cannot translate entity #{entity_name.inspect} to LaTeX."
-			return entity_name
-		end
-	end
-	
-	class LatexEntity
-		safe_attr_accessor :html_num, Fixnum
-		safe_attr_accessor :html_entity, String
-		safe_attr_accessor :latex_string, String
-		safe_attr_accessor :latex_packages, Array
-	end
-	
-	def Latex.need_entity_table
-		Latex.init_entity_table if ENTITY_TABLE.empty?
-	end
-	
-	# create hash @@entity_to_latex
-	def Latex.init_entity_table
-#		$stderr.write "Creating entity table.."
-#		$stderr.flush
-		doc = Document.new XML_TABLE
-		doc.elements.each("//char") do |c| 
-			num =  c.attributes['num'].to_i
-			name =  c.attributes['name']
-			package =  c.attributes['package']
-			
-			convert =  c.attributes['convertTo']
-			convert.gsub!(/@DOUBLEQUOT/,'"')
-			convert.gsub!(/@QUOT/,"'")
-			convert.gsub!(/@GT/,">")
-			convert.gsub!(/@LT/,"<")
-			convert.gsub!(/@AMP/,"&")
-			convert.freeze
-			
-			e = LatexEntity.new
-			e.html_num = num
-			e.html_entity = name
-			e.latex_string = convert
-			e.latex_packages = package ? package.split : []
-			
-			ENTITY_TABLE[num] = e
-			ENTITY_TABLE[name] = e
-		end
-#		$stderr.puts "..done."
-	end
-	
-	ENTITY_TABLE = {}
-
-# The following is a conversion chart for html elements, courtesy of 
-# text2html 
-
-	XML_TABLE ="
-	<chars>
-	  <char num='913' name='Alpha' convertTo='$A$' />
-	  <char num='914' name='Beta' convertTo='$B$' />
-	  <char num='915' name='Gamma' convertTo='$\\Gamma$' />
-	  <char num='916' name='Delta' convertTo='$\\Delta$' />
-	  <char num='917' name='Epsilon' convertTo='$E$' />
-	  <char num='918' name='Zeta' convertTo='$Z$' />
-	  <char num='919' name='Eta' convertTo='$H$' />
-	  <char num='920' name='Theta' convertTo='$\\Theta$' />
-	  <char num='921' name='Iota' convertTo='$I$' />
-	  <char num='922' name='Kappa' convertTo='$K$' />
-	  <char num='923' name='Lambda' convertTo='$\\Lambda$' />
-	  <char num='924' name='Mu' convertTo='$M$' />
-	  <char num='925' name='Nu' convertTo='$N$' />
-	  <char num='926' name='Xi' convertTo='$\\Xi$' />
-	  <char num='927' name='Omicron' convertTo='$O$' />
-	  <char num='928' name='Pi' convertTo='$\\Pi$' />
-	  <char num='929' name='Rho' convertTo='$P$' />
-	  <char num='931' name='Sigma' convertTo='$\\Sigma$' />
-	  <char num='932' name='Tau' convertTo='$T$' />
-	  <char num='933' name='Upsilon' convertTo='$Y$' />
-	  <char num='934' name='Phi' convertTo='$\\Phi$' />
-	  <char num='935' name='Chi' convertTo='$X$' />
-	  <char num='936' name='Psi' convertTo='$\\Psi$' />
-	  <char num='937' name='Omega' convertTo='$\\Omega$' />
-	  <char num='945' name='alpha' convertTo='$\\alpha$' />
-	  <char num='946' name='beta' convertTo='$\\beta$' />
-	  <char num='947' name='gamma' convertTo='$\\gamma$' />
-	  <char num='948' name='delta' convertTo='$\\delta$' />
-	  <char num='949' name='epsilon' convertTo='$\\epsilon$' />
-	  <char num='950' name='zeta' convertTo='$\\zeta$' />
-	  <char num='951' name='eta' convertTo='$\\eta$' />
-	  <char num='952' name='theta' convertTo='$\\theta$' />
-	  <char num='953' name='iota' convertTo='$\\iota$' />
-	  <char num='954' name='kappa' convertTo='$\\kappa$' />
-	  <char num='955' name='lambda' convertTo='$\\lambda$' />
-	  <char num='956' name='mu' convertTo='$\\mu$' />
-
-	  <char num='957' name='nu' convertTo='$\\nu$' />
-	  <char num='958' name='xi' convertTo='$\\xi$' />
-	  <char num='959' name='omicron' convertTo='$o$' />
-	  <char num='960' name='pi' convertTo='$\\pi$' />
-	  <char num='961' name='rho' convertTo='$\\rho$' />
-	  <char num='963' name='sigma' convertTo='$\\sigma$' />
-	  <char num='964' name='tau' convertTo='$\\tau$' />
-	  <char num='965' name='upsilon' convertTo='$\\upsilon$' />
-	  <char num='966' name='phi' convertTo='$\\phi$' />
-
-	  <char num='967' name='chi' convertTo='$\\chi$' />
-	  <char num='968' name='psi' convertTo='$\\psi$' />
-	  <char num='969' name='omega' convertTo='$\\omega$' />
-	  <char num='962' name='sigmaf' convertTo='$\\varsigma$' />
-	  <char num='977' name='thetasym' convertTo='$\\vartheta$' />
-	  <char num='982' name='piv' convertTo='$\\varpi$' />
-	  <char num='8230' name='hellip' convertTo='\\ldots' />
-	  <char num='8242' name='prime' convertTo='$\\prime$' />
-	  <char num='8254' name='oline' convertTo='-' />
-
-	  <char num='8260' name='frasl' convertTo='/' />
-	  <char num='8472' name='weierp' convertTo='$\\wp$' />
-	  <char num='8465' name='image' convertTo='$\\Im$' />
-	  <char num='8476' name='real' convertTo='$\\Re$' />
-	  <char num='8501' name='alefsym' convertTo='$\\aleph$' />
-	  <char num='8226' name='bull' convertTo='$\\bullet$' />
-	  <char num='8482' name='trade' convertTo='$^{\\rm TM}$' /> <!-- \texttrademark -->
-	  <char num='8592' name='larr' convertTo='$\\leftarrow$' />
-
-	  <char num='8594' name='rarr' convertTo='$\\rightarrow$' />
-	  <char num='8593' name='uarr' convertTo='$\\uparrow$' />
-	  <char num='8595' name='darr' convertTo='$\\downarrow$' />
-	  <char num='8596' name='harr' convertTo='$\\leftrightarrow$' />
-	  <char num='8629' name='crarr' convertTo='$\\hookleftarrow$' />
-	  <char num='8657' name='uArr' convertTo='$\\Uparrow$' />
-	  <char num='8659' name='dArr' convertTo='$\\Downarrow$' />
-	  <char num='8656' name='lArr' convertTo='$\\Leftarrow$' />
-	  <char num='8658' name='rArr' convertTo='$\\Rightarrow$' />
-
-	  <char num='8660' name='hArr' convertTo='$\\Leftrightarrow$' />
-	  <char num='8704' name='forall' convertTo='$\\forall$' />
-	  <char num='8706' name='part' convertTo='$\\partial$' />
-	  <char num='8707' name='exist' convertTo='$\\exists$' />
-	  <char num='8709' name='empty' convertTo='$\\emptyset$' />
-	  <char num='8711' name='nabla' convertTo='$\\nabla$' />
-	  <char num='8712' name='isin' convertTo='$\\in$' />
-	  <char num='8715' name='ni' convertTo='$\\ni$' />
-	  <char num='8713' name='notin' convertTo='$\\notin$' />
-
-	  <char num='8721' name='sum' convertTo='$\\sum$' />
-	  <char num='8719' name='prod' convertTo='$\\prod$' />
-	  <char num='8722' name='minus' convertTo='$-$' />
-	  <char num='8727' name='lowast' convertTo='$\\ast$' />
-	  <char num='8730' name='radic' convertTo='$\\surd$' />
-	  <char num='8733' name='prop' convertTo='$\\propto$' />
-	  <char num='8734' name='infin' convertTo='$\\infty$' />
-	  <char num='8736' name='ang' convertTo='$\\angle$' />
-	  <char num='8743' name='and' convertTo='$\\wedge$' />
-
-	  <char num='8744' name='or' convertTo='$\\vee$' />
-	  <char num='8745' name='cup' convertTo='$\\cup$' />
-	  <char num='8746' name='cap' convertTo='$\\cap$' />
-	  <char num='8747' name='int' convertTo='$\\int$' />
-	  <char num='8756' name='there4' convertTo='$\\therefore$' package='amssymb' /> <!-- only AMS -->
-	  <char num='8764' name='sim' convertTo='$\\sim$' />
-	  <char num='8776' name='asymp' convertTo='$\\approx$' />
-	  <char num='8773' name='cong' convertTo='$\\cong$' />
-
-	  <char num='8800' name='ne' convertTo='$\\neq$' />
-	  <char num='8801' name='equiv' convertTo='$\\equiv$' />
-	  <char num='8804' name='le' convertTo='$\\leq$' />
-	  <char num='8805' name='ge' convertTo='$\\geq$' />
-	  <char num='8834' name='sub' convertTo='$\\subset$' />
-	  <char num='8835' name='sup' convertTo='$\\supset$' />
-<!--	  <char num='8838' name='sube' convertTo='$\\subseteq$' />-->
-	  <char num='8839' name='supe' convertTo='$\\supseteq$' />
-<!--	  <char num='8836' name='nsub' convertTo='$\\nsubset$'  /> --><!-- only AMS -->
-
-	  <char num='8853' name='oplus' convertTo='$\\oplus$' />
-	  <char num='8855' name='otimes' convertTo='$\\otimes$' />
-	  <char num='8869' name='perp' convertTo='$\\perp$' />
-	  <char num='8901' name='sdot' convertTo='$\\cdot$' />
-	  <char num='8968' name='rceil' convertTo='$\\rceil$' />
-	  <char num='8969' name='lceil' convertTo='$\\lceil$' />
-	  <char num='8970' name='lfloor' convertTo='$\\lfloor$' />
-	  <char num='8971' name='rfloor' convertTo='$\\rfloor$' />
-	  <char num='9001' name='rang' convertTo='$\\rangle$' />
-
-	  <char num='9002' name='lang' convertTo='$\\langle$' />
-	  <char num='9674' name='loz' convertTo='$\\lozenge$' package='amssymb' /> <!-- only AMS -->
-	  <char num='9824' name='spades' convertTo='$\\spadesuit$' />
-	  <char num='9827' name='clubs' convertTo='$\\clubsuit$' />
-	  <char num='9829' name='hearts' convertTo='$\\heartsuit$' />
-	  <char num='9830' name='diams' convertTo='$\\diamondsuit$' />                                     
-	  <char num='38' name='amp' convertTo='\\@AMP' />    
-<!--	  <char num='34' name='quot' convertTo='\\@DOUBLEQUOT' />  XXX -->
-	<char num='34' name='quot' convertTo='\"' /> 
-	<char num='39' name='apos' convertTo=\"'\" /> 
-	  <char num='169' name='copy' convertTo='\\copyright' />
-
-	  <char num='60' name='lt' convertTo='$@LT$' />
-	  <char num='62' name='gt' convertTo='$@GT$' />
-	  <char num='338' name='OElig' convertTo='\\OE' />
-	  <char num='339' name='oelig' convertTo='\\oe' />
-	  <char num='352' name='Scaron' convertTo='\\v{S}' />
-	  <char num='353' name='scaron' convertTo='\\v{s}' />
-	  <char num='376' name='Yuml' convertTo='\\\"Y' />
-	  <char num='710' name='circ' convertTo='\\textasciicircum' />
-	  <char num='732' name='tilde' convertTo='\\textasciitilde' />
-
-	  <char num='8211' name='ndash' convertTo='--' />
-	  <char num='8212' name='mdash' convertTo='---' />
-	  <char num='8216' name='lsquo' convertTo='`' />
-	  <char num='8217' name='rsquo' convertTo=\"'\" /> <!-- XXXX -->
-	  <char num='8220' name='ldquo' convertTo='``' />
-	  <char num='8221' name='rdquo' convertTo=\"''\" /> <!-- XXXX -->
-	  <char num='8224' name='dagger' convertTo='\\dag' />
-	  <char num='8225' name='Dagger' convertTo='\\ddag' />
-	  <char num='8240' name='permil' convertTo='\\permil' package='wasysym' /> <!-- wasysym package -->
-
-	  <char num='8364' name='euro' convertTo='\\euro' package='eurosym' /> <!-- eurosym package -->
-	  <char num='8249' name='lsaquo' convertTo='\\guilsinglleft' package='aeguill'/>
-	  <char num='8250' name='rsaquo' convertTo='\\guilsinglright' package='aeguill' />
-<!--	  <char num='160' name='nbsp' convertTo='\\nolinebreak' />-->
-	  <char num='160' name='nbsp' convertTo='~' />
-	  <char num='161' name='iexcl' convertTo='\\textexclamdown' />
-	  <char num='163' name='pound' convertTo='\\pounds' />
-	  <char num='164' name='curren' convertTo='\\currency' package='wasysym' /> <!-- wasysym package -->
-	  <char num='165' name='yen' convertTo='\\textyen' package='textcomp'/> <!-- textcomp -->
-
-	  <char num='166' name='brvbar' convertTo='\\brokenvert' /> <!-- wasysym -->
-	  <char num='167' name='sect' convertTo='\\S' />
-	  <char num='171' name='laquo' convertTo='\\guillemotleft' package='aeguill'/>
-	  <char num='187' name='raquo' convertTo='\\guillemotright' package='aeguill'/>
-	  <char num='174' name='reg' convertTo='\\textregistered' />
-	  <char num='170' name='ordf' convertTo='\\textordfeminine' />
-	  <char num='172' name='not' convertTo='$\\neg$' />
-	<!--  <char num='176' name='deg' convertTo='$\\degree$' /> --><!-- mathabx -->
-	  <char num='176' name='deg' convertTo='\\textdegree' package='textcomp'/>
-
-	  <char num='177' name='plusmn' convertTo='$\\pm$' />
-	  <char num='180' name='acute' convertTo='@QUOT' />
-	  <char num='181' name='micro' convertTo='$\\mu$' />
-	  <char num='182' name='para' convertTo='\\P' />
-	  <char num='183' name='middot' convertTo='$\\cdot$' />
-	  <char num='186' name='ordm' convertTo='\\textordmasculine' />
-	  <char num='162' name='cent' convertTo='\\cent' package='wasysym' /> 
-	  <char num='185' name='sup1' convertTo='$^1$' />
-
-	  <char num='178' name='sup2' convertTo='$^2$' />
-	  <char num='179' name='sup3' convertTo='$^3$' />
-	  <char num='189' name='frac12' convertTo='$\\frac{1}{2}$' />
-	  <char num='188' name='frac14' convertTo='$\\frac{1}{4}$' />
-	  <char num='190' name='frac34' convertTo='$\\frac{3}{4}$' />
-	  <char num='192' name='Agrave' convertTo='\\`A' />
-	  <char num='193' name='Aacute' convertTo='\\@QUOTA' />
-	  <char num='194' name='Acirc' convertTo='\\^A' />
-	  <char num='195' name='Atilde' convertTo='\\~A' />
-
-	  <char num='196' name='Auml' convertTo='\\@DOUBLEQUOTA' />
-	  <char num='197' name='Aring' convertTo='\\AA' />
-	  <char num='198' name='AElig' convertTo='\\AE' />
-	  <char num='199' name='Ccedil' convertTo='\\c{C}' />
-	  <char num='200' name='Egrave' convertTo='\\`E' />
-	  <char num='201' name='Eacute' convertTo='\\@QUOTE' />
-	  <char num='202' name='Ecirc' convertTo='\\^E' />
-	  <char num='203' name='Euml' convertTo='\\@DOUBLEQUOTE' />
-	  <char num='204' name='Igrave' convertTo='\\`I' />
-	  <char num='205' name='Iacute' convertTo='\\@QUOTI' />
-	  <char num='206' name='Icirc' convertTo='\\^I' />
-	  <char num='207' name='Iuml' convertTo='\\\"I' />
-	  <char num='208' name='ETH' convertTo='$\\eth$' /> <!-- AMS -->
-	  <char num='209' name='Ntilde' convertTo='\\~N' />    
-	  <char num='210' name='Ograve' convertTo='\\`O' />
-	  <char num='211' name='Oacute' convertTo='\\@QUOT O' />
-	  <char num='212' name='Ocirc' convertTo='\\^O' />
-	  <char num='213' name='Otilde' convertTo='\\~O' />
-	  <char num='214' name='Ouml' convertTo='\\@DOUBLEQUOTO' />
-	  <char num='215' name='times' convertTo='$\\times$' />
-	  <char num='216' name='Oslash' convertTo='\\O' />
-	  <char num='217' name='Ugrave' convertTo='\\`U' />
-	  <char num='218' name='Uacute' convertTo='\\@QUOTU' />
-	  <char num='219' name='Ucirc' convertTo='\\^U' />
-	  <char num='220' name='Uuml' convertTo='\\@DOUBLEQUOTU' />
-	  <char num='221' name='Yacute' convertTo='\\@QUOTY' />
-	  <char num='223' name='szlig' convertTo='\\ss' />
-	  <char num='224' name='agrave' convertTo='\\`a' />
-	  <char num='225' name='aacute' convertTo='\\@QUOTa' />
-	  <char num='226' name='acirc' convertTo='\\^a' />
-	  <char num='227' name='atilde' convertTo='\\~a' />
-	  <char num='228' name='auml' convertTo='\\@DOUBLEQUOTa' />
-	  <char num='229' name='aring' convertTo='\\aa' />
-	  <char num='230' name='aelig' convertTo='\\ae' />
-	  <char num='231' name='ccedil' convertTo='\\c{c}' />
-	  <char num='232' name='egrave' convertTo='\\`e' />
-	  <char num='233' name='eacute' convertTo='\\@QUOTe' />
-	  <char num='234' name='ecirc' convertTo='\\^e' />
-	  <char num='235' name='euml' convertTo='\\@DOUBLEQUOTe' />    
-	  <char num='236' name='igrave' convertTo='\\`i' />
-	  <char num='237' name='iacute' convertTo='\\@QUOTi' />
-	  <char num='238' name='icirc' convertTo='\\^i' />
-	  <char num='239' name='iuml' convertTo='\\@DOUBLEQUOTi' />
-	  <char num='240' name='eth' convertTo='$\\eth$' package='amssymb'/> <!-- -->
-	  <char num='241' name='ntilde' convertTo='\\~n' />
-	  <char num='242' name='ograve' convertTo='\\`o' />
-	  <char num='243' name='oacute' convertTo='\\@QUOTo' />
-	  <char num='244' name='ocirc' convertTo='\\^o' />
-	  <char num='245' name='otilde' convertTo='\\~o' />
-	  <char num='246' name='ouml' convertTo='\\@DOUBLEQUOTo' />
-<!--   <char num='247' name='divide' convertTo='$\\divide$' />       -->
-	  <char num='248' name='oslash' convertTo='\\o' /> 
-	  <char num='249' name='ugrave' convertTo='\\`u' />
-	  <char num='250' name='uacute' convertTo='\\@QUOTu' />
-	  <char num='251' name='ucirc' convertTo='\\^u' />
-	  <char num='252' name='uuml' convertTo='\\@DOUBLEQUOTu' />
-	  <char num='253' name='yacute' convertTo='\\@QUOTy' />
-
-	  <char num='255' name='yuml' convertTo='\\@DOUBLEQUOTy' />                  
-
-		<char num='222' name='THORN' convertTo='\\Thorn' package='wasysym' /> 
-		<char num='254' name='thorn' convertTo='\\thorn' package='wasysym' />
-	</chars>"
-	
-
-end end end
-
diff --git a/lib/maruku/output/to_latex_strings.rb b/lib/maruku/output/to_latex_strings.rb
deleted file mode 100644
index da043a7..0000000
--- a/lib/maruku/output/to_latex_strings.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-
-class String
-
-	# These are TeX's special characters
-	LATEX_ADD_SLASH = [ ?{, ?}, ?$, ?&, ?#, ?_, ?%]
-
-	# These, we transform to {\tt \char<ascii code>}
-	LATEX_TO_CHARCODE = [ ?^, ?~, ?>,?<]
-
-	def escape_to_latex(s)
-		s2 = ""
-		s.each_byte do |b|
-			if LATEX_TO_CHARCODE.include? b
-				s2 += "{\\tt \\char#{b}}" 
-			elsif LATEX_ADD_SLASH.include? b
-				s2 << ?\\ << b
-			elsif b == ?\\
-			# there is no backslash in cmr10 fonts
-				s2 += "$\\backslash$"
-			else
-				s2 << b
-			end
-		end
-		s2
-	end
-	
-	# escapes special characters
-	def to_latex
-		s = escape_to_latex(self)
-		OtherGoodies.each do |k, v|
-			s.gsub!(k, v)
-		end
-		s
-	end
-	
-	# other things that are good on the eyes
-	OtherGoodies = {
-		/(\s)LaTeX/ => '\1\\LaTeX\\xspace ', # XXX not if already \LaTeX
-#		'HTML' => '\\textsc{html}\\xspace ',
-#		'PDF' => '\\textsc{pdf}\\xspace '
-	}
-	
-end
\ No newline at end of file
diff --git a/lib/maruku/output/to_markdown.rb b/lib/maruku/output/to_markdown.rb
index 98d9322..eb3ea09 100644
--- a/lib/maruku/output/to_markdown.rb
+++ b/lib/maruku/output/to_markdown.rb
@@ -1,164 +1,209 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-class String
-	# XXX: markdown escaping
-	def to_md(c=nil)
-		to_s
-	end
-	
-	# " andrea censi " => [" andrea ", "censi "]
-	def mysplit
-		split.map{|x| x+" "}
-	end
-end
+module MaRuKu::Out::Markdown
+
+  DefaultLineLength = 40
+
+  def to_md(context={})
+    children_to_md(context)
+  end
+
+  # " andrea censi " => [" andrea ", "censi "]
+  def mysplit(c)
+    res = c.split.map {|x| x + " " }
+    if c[0] == ' ' && res[0]
+      res[0] = " " + res[0]
+    end
+    res
+  end
+
+  def to_md_header(context)
+    pounds = "#" * @level
+    "#{pounds} #{children_to_md(context)} #{pounds}\n\n"
+  end
+
+  def to_md_inline_code(context)
+    "`#{@raw_code}`"
+  end
+
+  def to_md_code(context)
+    @raw_code.split("\n").collect { |line| "     " + line}.join("\n") + "\n\n"
+  end
+
+  def to_md_quote(context)
+    line_length = (context[:line_length] || DefaultLineLength) - 2
+    wrap(@children, line_length, context).split(/\n/).collect { |line| "> " + line}.join("\n") + "\n"
+  end
+
+  def to_md_hrule(context)
+    "* * *\n"
+  end
+
+  def to_md_emphasis(context)
+    "*#{children_to_md(context)}*"
+  end
+
+  def to_md_strong(context)
+    "**#{children_to_md(context)}**"
+  end
+
+  def to_md_immediate_link(context)
+    "<#{@url}>"
+  end
+
+  def to_md_email_address(context)
+    "<#{@email}>"
+  end
+
+  def to_md_entity(context)
+    "&#{@entity_name};"
+  end
+
+  def to_md_linebreak(context)
+    "\n"
+  end
+
+  def to_md_paragraph(context)
+    line_length = context[:line_length] || DefaultLineLength
+    wrap(@children, line_length, context)+"\n"
+  end
+
+  def to_md_im_link(context)
+    "[#{children_to_md(context)}](#{@url}#{" \"#{@title}\"" if @title})"
+  end
+
+  def to_md_link(context)
+    "[#{children_to_md(context)}][#{@ref_id}]"
+  end
+
+  def to_md_im_image(context)
+    "![#{children_to_md(context)}](#{@url}#{" \"#{@title}\"" if @title})"
+  end
 
+  def to_md_image(context)
+    "![#{children_to_md(context)}][#{@ref_id}]"
+  end
 
-module MaRuKu; module Out; module Markdown 
-	
-	DefaultLineLength = 40
-	
-	def to_md(context={})
-		children_to_md(context)
-	end
-	
-	def to_md_paragraph(context)
-		line_length = context[:line_length] || DefaultLineLength
-		wrap(@children, line_length, context)+"\n"
-	end
-	
-	def to_md_li_span(context)
-		len = (context[:line_length] || DefaultLineLength) - 2
-		s = add_tabs(wrap(@children, len-2, context), 1, '  ')
-		s[0] = ?*
-		s + "\n"
-	end
-	
-	def to_md_abbr_def(context)
-		"*[#{self.abbr}]: #{self.text}\n"
-	end
-	
-	def to_md_ol(context)
-		len = (context[:line_length] || DefaultLineLength) - 2
-		md = ""
-		self.children.each_with_index do |li, i|
-			s = add_tabs(w=wrap(li.children, len-2, context), 1, '    ')+"\n"
-			s[0,4] = "#{i+1}.  "[0,4]
-#			puts w.inspect
-			md += s
-		end
-		md + "\n"
-	end
-
-	def to_md_ul(context)
-		len = (context[:line_length] || DefaultLineLength) - 2
-		md = ""
-		self.children.each_with_index do |li, i|
-			w = wrap(li.children, len-2, context)
-#			puts "W: "+ w.inspect
-			s = add_indent(w)
-#			puts "S: " +s.inspect
-			s[0,1] = "-"
-			md += s
-		end
-		md + "\n"
-	end
-	
-	def add_indent(s,char="    ")
-		t = s.split("\n").map{|x| char+x }.join("\n")
-		s << ?\n if t[-1] == ?\n
-		s
-	end
-	
-	# Convert each child to html
-	def children_to_md(context)
-		array_to_md(@children, context)
-	end
-	
-	def wrap(array, line_length, context)
-		out = ""
-		line = ""
-		array.each do |c|
-			if c.kind_of?(MDElement) &&  c.node_type == :linebreak
-				out << line.strip << "  \n"; line="";
-				next
-			end
-		
-			pieces =
-			if c.kind_of? String
-				c.to_md.mysplit
-			else
-				[c.to_md(context)].flatten
-			end
-		
-	#			puts "Pieces: #{pieces.inspect}"
-			pieces.each do |p|
-				if p.size + line.size > line_length
-					out << line.strip << "\n"; 
-					line = ""
-				end
-				line << p
-			end
-		end
-		out << line.strip << "\n" if line.size > 0
-		out << ?\n if not out[-1] == ?\n
-		out
-	end
-
-
-	def array_to_md(array, context, join_char='')
-		e = []
-		array.each do |c|
-			method = c.kind_of?(MDElement) ? 
-			   "to_md_#{c.node_type}" : "to_md"
-			
-			if not c.respond_to?(method)
-				#raise "Object does not answer to #{method}: #{c.class} #{c.inspect[0,100]}"
-#				tell_user "Using default for #{c.node_type}"
-				method = 'to_md'
-			end
-			
-#			puts "#{c.inspect} created with method #{method}"
-			h =  c.send(method, context)
-			
-			if h.nil?
-				raise "Nil md for #{c.inspect} created with method #{method}"
-			end
-			
-			if h.kind_of?Array
-				e = e + h
-			else
-				e << h
-			end
-		end
-		e.join(join_char)
-	end
-	
-end end end
-
-module MaRuKu; class MDDocument
-	alias old_md to_md
-	def to_md(context={})
-		s = old_md(context)
-#		puts s
-		s
-	end	
-end end
\ No newline at end of file
+  def to_md_ref_definition(context)
+    "[#{@ref_id}] #{@url}#{" \"#{@title}\"" if @title}"
+  end
+
+  def to_md_abbr_def(context)
+    "*[#{self.abbr}]: #{self.text}\n"
+  end
+
+  def to_md_ol(context)
+    len = (context[:line_length] || DefaultLineLength) - 2
+    md = ""
+    self.children.each_with_index do |li, i|
+      #     s = (w=wrap(li.children, len-2, context)).rstrip.gsub(/^/, '    ')+"\n"
+      #     s[0,4] = "#{i+1}.  "[0,4]
+      #     puts w.inspect
+      s = "#{i+1}. " + wrap(li.children, len-2, context).rstrip + "\n"
+      md += s
+    end
+    md + "\n"
+  end
+
+  def to_md_ul(context)
+    len = (context[:line_length] || DefaultLineLength) - 2
+    md = ""
+    self.children.each_with_index do |li, i|
+      w = wrap(li.children, len-2, context)
+      s = "- " + w
+      #     puts "W: "+ w.inspect
+      #   s = add_indent(w)
+      #     puts "S: " +s.inspect
+      #   s[0,1] = "-"
+      md += s
+    end
+    md + "\n"
+  end
+
+  def add_indent(s,char="    ")
+    t = s.split("\n").map{|x| char+x }.join("\n")
+    s << ?\n if t[-1] == ?\n
+    s
+  end
+
+  # Convert each child to html
+  def children_to_md(context)
+    array_to_md(@children, context)
+  end
+
+  def wrap(array, line_length, context)
+    out = ""
+    line = ""
+    array.each do |c|
+      if c.kind_of?(MaRuKu::MDElement) &&  c.node_type == :linebreak
+        out << line.strip << "  \n"; line="";
+        next
+      end
+
+      pieces =
+        if c.kind_of? String
+          mysplit(c)
+        elsif c.kind_of?(MaRuKu::MDElement)
+          method = "to_md_#{c.node_type}"
+          method = "to_md" unless c.respond_to?(method)
+          [c.send(method, context)].flatten
+        else
+          [c.to_md(context)].flatten
+        end
+
+      #     puts "Pieces: #{pieces.inspect}"
+      pieces.each do |p|
+        if p.size + line.size > line_length
+          out << line.strip << "\n";
+          line = ""
+        end
+        line << p
+      end
+    end
+    out << line.strip << "\n" if line.size > 0
+    out << ?\n if not out[-1] == ?\n
+    out
+  end
+
+
+  def array_to_md(array, context, join_char='')
+    e = []
+    array.each do |c|
+      if c.is_a?(String)
+        e << c
+      else
+        method = c.kind_of?(MaRuKu::MDElement) ?
+        "to_md_#{c.node_type}" : "to_md"
+
+        if not c.respond_to?(method)
+          #raise "Object does not answer to #{method}: #{c.class} #{c.inspect[0,100]}"
+          #       tell_user "Using default for #{c.node_type}"
+          method = 'to_md'
+        end
+
+        #     puts "#{c.inspect} created with method #{method}"
+        h =  c.send(method, context)
+
+        if h.nil?
+          raise "Nil md for #{c.inspect} created with method #{method}"
+        end
+
+        if h.kind_of?Array
+          e = e + h
+        else
+          e << h
+        end
+      end
+    end
+    e.join(join_char)
+  end
+
+end
+
+module MaRuKu
+  class MDDocument
+    alias old_md to_md
+    def to_md(context={})
+      warn "Maruku#to_md is deprecated and will be removed in a near-future version of Maruku."
+      old_md(context)
+    end
+  end
+end
diff --git a/lib/maruku/output/to_s.rb b/lib/maruku/output/to_s.rb
index ecdadd9..401a5ed 100644
--- a/lib/maruku/output/to_s.rb
+++ b/lib/maruku/output/to_s.rb
@@ -1,56 +1,14 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
 module MaRuKu
-	
-class MDElement
-	
-	# Strips all formatting from the string
-	def to_s
-		 children_to_s
-	end
-	
-	def children_to_s
-		@children.join
-	end
-	
-	# Generate an id for headers. Assumes @children is set.
-	def generate_id
-		
-		title = children_to_s
-		title.gsub!(/ /,'_')
-		title.downcase!
-		title.gsub!(/[^\w_]/,'')
-		title.strip!
-		
-		if title.size == 0
-			$uid ||= 0
-			$uid += 1
-			title = "id#{$uid}"
-		end
 
-		# random is a very bad idea
-#		title << "_" + rand(10000).to_s
-		title
-	end
-end
+  class MDElement
+
+    # Strips all formatting from the string
+    def to_s
+      children_to_s
+    end
 
+    def children_to_s
+      @children.join
+    end
+  end
 end
diff --git a/lib/maruku/string_utils.rb b/lib/maruku/string_utils.rb
index e041804..4e55c0a 100644
--- a/lib/maruku/string_utils.rb
+++ b/lib/maruku/string_utils.rb
@@ -1,191 +1,141 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
+require 'strscan'
 
+module MaRuKu
+  # Utility functions for dealing with strings.
+  module Strings
+    TAB_SIZE = 4
 
-# Boring stuff with strings.
-module MaRuKu; module Strings
-	
-	def add_tabs(s,n=1,char="\t")
-		s.split("\n").map{|x| char*n+x }.join("\n")
-	end
-	
-	TabSize = 4;
-	
-	def split_lines(s)
-		s.gsub("\r","").split("\n")
-	end
-	
-	# This parses email headers. Returns an hash. 
-	#
-	# +hash['data']+ is the message.
-	#
-	# Keys are downcased, space becomes underscore, converted to symbols.
-	#
-	#     My key: true
-	#
-	# becomes:
-	#
-	#     {:my_key => true}
-	#
-	def parse_email_headers(s)
-		keys={}
-		match = (s =~ /\A((\w[\w\s\_\-]+: .*\n)+)\s*\n/)
-		if match != 0
-			keys[:data] = s
-		else
-			keys[:data] = $'
-			headers = $1
-			headers.split("\n").each do |l| 
-# Fails if there are other ':' characters.
-#				k, v = l.split(':')
-				k, v = l.split(':', 2)
-				k, v = normalize_key_and_value(k, v)
-				k = k.to_sym
-#				puts "K = #{k}, V=#{v}"
-				keys[k] = v
-			end
-		end
-		keys
-	end
+    # Split a string into multiple lines,
+    # on line feeds and/or carriage returns.
+    #
+    # @param s [String]
+    # @return [String]
+    def split_lines(s)
+      s.split(/\r\n|\r|\n/)
+    end
 
-	# Keys are downcased, space becomes underscore, converted to symbols.
-	def normalize_key_and_value(k,v)
-		v = v ? v.strip : true # no value defaults to true
-		k = k.strip
-		
-		# check synonyms
-		v = true if ['yes','true'].include?(v.to_s.downcase)
-		v = false if ['no','false'].include?(v.to_s.downcase)
-	
-		k = k.downcase.gsub(' ','_')
-		return k, v
-	end
-	
-	# Returns the number of leading spaces, considering that
-	# a tab counts as `TabSize` spaces.
-	def number_of_leading_spaces(s)
-		n=0; i=0;
-		while i < s.size 
-			c = s[i,1]
-			if c == ' '
-				i+=1; n+=1;
-			elsif c == "\t"
-				i+=1; n+=TabSize;
-			else
-				break
-			end
-		end
-		n
-	end
+    # Parses email headers, returning a hash.
+    # `hash[:data]` is the message;
+    # that is, anything past the headers.
+    #
+    # Keys are downcased and converted to symbols;
+    # spaces become underscores. For example:
+    #
+    #     !!!plain
+    #     My key: true
+    #
+    # becomes:
+    #
+    #     {:my_key => true}
+    #
+    # @param s [String] The email
+    # @return [Symbol => String] The header values
+    def parse_email_headers(s)
+      headers = {}
+      scanner = StringScanner.new(s)
 
-	# This returns the position of the first real char in a list item
-	#
-	# For example: 
-	#     '*Hello' # => 1
-	#     '* Hello' # => 2
-	#     ' * Hello' # => 3
-	#     ' *   Hello' # => 5
-	#     '1.Hello' # => 2
-	#     ' 1.  Hello' # => 5
-	
-	def spaces_before_first_char(s)
-		case s.md_type
-		when :ulist
-			i=0;
-			# skip whitespace if present
-			while s[i,1] =~ /\s/; i+=1 end
-			# skip indicator (+, -, *)
-			i+=1
-			# skip optional whitespace
-			while s[i,1] =~ /\s/; i+=1 end
-			return i
-		when :olist
-			i=0;
-			# skip whitespace
-			while s[i,1] =~ /\s/; i+=1 end
-			# skip digits
-			while s[i,1] =~ /\d/; i+=1 end
-			# skip dot
-			i+=1
-			# skip whitespace
-			while s[i,1] =~ /\s/; i+=1 end
-			return i
-		else
-			tell_user "BUG (my bad): '#{s}' is not a list"
-			0
-		end
-	end
+      while scanner.scan(/(\w[\w\s\-]+): +(.*)\n/)
+        k, v = normalize_key_and_value(scanner[1], scanner[2])
+        headers[k.to_sym] = v
+      end
 
-	# Counts the number of leading '#' in the string
-	def num_leading_hashes(s)
-		i=0;
-		while i<(s.size-1) && (s[i,1]=='#'); i+=1 end
-		i	
-	end
-	
-	# Strips initial and final hashes
-	def strip_hashes(s)
-		s = s[num_leading_hashes(s), s.size]
-		i = s.size-1
-		while i > 0 && (s[i,1] =~ /(#|\s)/); i-=1; end
-		s[0, i+1].strip
-	end
-	
-	# change space to "_" and remove any non-word character
-	def sanitize_ref_id(x)
-		x.strip.downcase.gsub(' ','_').gsub(/[^\w]/,'')
-	end
+      headers[:data] = scanner.rest
+      headers
+    end
 
+    # This returns the position of the first non-list character
+    # in a list item.
+    #
+    # @example
+    # spaces_before_first_char('*Hello') #=> 1
+    # spaces_before_first_char('* Hello') #=> 2
+    # spaces_before_first_char(' * Hello') #=> 3
+    # spaces_before_first_char(' *   Hello') #=> 5
+    # spaces_before_first_char('1.Hello') #=> 2
+    # spaces_before_first_char(' 1.  Hello') #=> 5
+    #
+    # @param s [String]
+    # @return [Fixnum]
+    def spaces_before_first_char(s)
+      s = MaRuKu::MDLine.new(s.gsub(/([^\t]*)(\t)/) { $1 + " " * (TAB_SIZE - $1.length % TAB_SIZE) })
+      match = case s.md_type
+        when :ulist
+          # whitespace, followed by ('*'|'+'|'-') followed by
+          # more whitespace, followed by an optional IAL, followed
+          # by yet more whitespace
+          s[/^\s*(\*|\+|\-)\s*(\{[:#\.].*?\})?\s*/]
+        when :olist
+          # whitespace, followed by a number, followed by a period,
+          # more whitespace, an optional IAL, and more whitespace
+          s[/^\s*\d+\.\s*(\{[:#\.].*?\})?\s*/]
+        else
+          tell_user "BUG (my bad): '#{s}' is not a list"
+          ''
+        end
+      f = /\{(.*?)\}/.match(match)
+      ial = f[1] if f
+      [match.length, ial]
+    end
 
-	# removes initial quote
-	def unquote(s)
-		s.gsub(/^>\s?/,'')
-	end
+    # Normalize a link reference.
+    #
+    # @param s [String]
+    # @return [String]
+    def sanitize_ref_id(s)
+      s.downcase.gsub(/\s+/, ' ')
+    end
 
-	# toglie al massimo n caratteri
-	def strip_indent(s, n) 
-		i = 0
-		while i < s.size && n>0
-			c = s[i,1]
-			if c == ' '
-				n-=1;
-			elsif c == "\t"
-				n-=TabSize;
-			else
-				break
-			end
-			i+=1
-		end
-		s[i, s.size]
-	end
+    # Remove line-initial `>` characters for a quotation.
+    #
+    # @param s [String]
+    # @return [String]
+    def unquote(s)
+      s.gsub(/^>\s?/, '')
+    end
 
-	def dbg_describe_ary(a, prefix='')
-		i = 0 
-		a.each do |l|
-			puts "#{prefix} (#{i+=1})# #{l.inspect}"
-		end
-	end
+    # Removes indentation from the beginning of `s`,
+    # up to at most `n` spaces.
+    # Tabs are counted as {TAB_SIZE} spaces.
+    #
+    # @param s [String]
+    # @param n [Fixnum]
+    # @return [String]
+    def strip_indent(s, n)
+      while n > 0
+        case s[0, 1]
+        when ' '
+          n -= 1
+        when "\t"
+          n -= TAB_SIZE
+        else
+          break
+        end
+        s = s[1..-1]
+      end
 
-	def force_linebreak?(l)
-		l =~ /  $/
-	end
+      MDLine.new(s)
+    end
 
-end
+    private
+
+    # Normalize the key/value pairs for email headers.
+    # Keys are downcased and converted to symbols;
+    # spaces become underscores.
+    #
+    # Values of `"yes"`, `"true"`, `"no"`, and `"false"`
+    # are converted to appropriate booleans.
+    #
+    # @param k [String]
+    # @param v [String]
+    # @return [Array(String, String or Boolean)]
+    def normalize_key_and_value(k, v)
+      k = k.strip.downcase.gsub(/\s+/, '_').to_sym
+      v = v.strip
+
+      # check synonyms
+      return k, true if %w[yes true].include?(v.downcase)
+      return k, false if %w[no false].include?(v.downcase)
+      return k, v
+    end
+  end
 end
diff --git a/lib/maruku/structures.rb b/lib/maruku/structures.rb
deleted file mode 100644
index 50e2314..0000000
--- a/lib/maruku/structures.rb
+++ /dev/null
@@ -1,167 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-
-class Module
-	def safe_attr_accessor1(symbol, klass)
-		attr_reader symbol
-		code = <<-EOF
-		def #{symbol}=(val)  
-			if not val.kind_of? #{klass}
-				s = "\nCould not assign an object of type \#{val.class} to #{symbol}.\n\n"
-				s += "Tried to assign object of class \#{val.class}:\n"+
-				     "\#{val.inspect}\n"+
-				     "to \#{self.class}::#{symbol} constrained to be of class #{klass}.\n"
-				raise s
-			end
-			@#{symbol} = val
-		end
-		
-EOF
-		module_eval code
-  end
-
-	def safe_attr_accessor2(symbol, klass)
-		attr_accessor symbol
-	end
-	
-	alias  safe_attr_accessor  safe_attr_accessor2
-end
-
-module MaRuKu
-	
-# I did not want to have a class for each possible element. 
-# Instead I opted to have only the class "MDElement"
-# that represents eveything in the document (paragraphs, headers, etc).
-#
-# You can tell what it is by the variable `node_type`. 
-#
-# In the instance-variable `children` there are the children. These
-# can be of class 1) String or 2) MDElement. 
-#
-# The @doc variable points to the document to which the MDElement
-# belongs (which is an instance of Maruku, subclass of MDElement).
-#
-# Attributes are contained in the hash `attributes`. 
-# Keys are symbols (downcased, with spaces substituted by underscores)
-#
-# For example, if you write in the source document.
-# 
-#     Title: test document
-#     My property: value
-#     
-#     content content
-#
-# You can access `value` by writing:
-#
-#     @doc.attributes[:my_property] # => 'value'
-#
-# from whichever MDElement in the hierarchy.
-#
-class MDElement 
-	# See helpers.rb for the list of allowed #node_type values
-	safe_attr_accessor :node_type, Symbol
-	
-	# Children are either Strings or MDElement
-	safe_attr_accessor :children, Array
-	
-	# An attribute list, may not be nil
-	safe_attr_accessor :al, Array #Maruku::AttributeList
-
-	# These are the processed attributes
-	safe_attr_accessor :attributes, Hash
-	
-	# Reference of the document (which is of class Maruku)
-	attr_accessor :doc
-	
-	def initialize(node_type=:unset, children=[], meta={}, 
-			al=MaRuKu::AttributeList.new )
-		super(); 
-		self.children = children
-		self.node_type = node_type
-		
-		@attributes = {}
-		
-		meta.each do |symbol, value|
-			self.instance_eval "
-			  def #{symbol}; @#{symbol}; end
-			  def #{symbol}=(val); @#{symbol}=val; end"
-			self.send "#{symbol}=", value
-		end
-		
-		self.al = al || AttributeList.new
-
-		self.meta_priv = meta
-	end
-	
-	attr_accessor :meta_priv
-	
-	def ==(o)
-		ok = o.kind_of?(MDElement) &&
-		(self.node_type == o.node_type) &&
-		(self.meta_priv == o.meta_priv) &&
-		(self.children == o.children)
-		
-		if not ok
-#			puts "This:\n"+self.inspect+"\nis different from\n"+o.inspect+"\n\n"
-		end
-		ok
-	end
-end
-
-# This represents the whole document and holds global data.
-
-class MDDocument
-	
-	safe_attr_accessor :refs, Hash
-	safe_attr_accessor :footnotes, Hash
-	
-	# This is an hash. The key might be nil.
-	safe_attr_accessor :abbreviations, Hash
-	
-	# Attribute lists definition
-	safe_attr_accessor :ald, Hash
-	
-	# The order in which footnotes are used. Contains the id.
-	safe_attr_accessor :footnotes_order, Array
-	
-	safe_attr_accessor :latex_required_packages, Array
-	
-	safe_attr_accessor :refid2ref, Hash
-	
-	def initialize(s=nil)
-		super(:document)
-		@doc       = self
-
-		self.refs = {}
-		self.footnotes = {}
-		self.footnotes_order = []
-		self.abbreviations = {}
-		self.ald = {}
-		self.latex_required_packages = []
-		
-		parse_doc(s) if s 
-	end
-end
-
-
-end # MaRuKu
-
diff --git a/lib/maruku/structures_inspect.rb b/lib/maruku/structures_inspect.rb
deleted file mode 100644
index c0064f9..0000000
--- a/lib/maruku/structures_inspect.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-
-class String
-	def inspect_more(a=nil,b=nil)
-		inspect
-	end
-end
-
-class Object
-	def inspect_more(a=nil,b=nil)
-		inspect
-	end
-end
-
-class Array
-	def inspect_more(compact, join_string, add_brackets=true)
-		s  = map {|x| 
-			x.kind_of?(String) ? x.inspect : 
-			x.kind_of?(MaRuKu::MDElement) ? x.inspect(compact) : 
-			(raise "WTF #{x.class} #{x.inspect}")
-		}.join(join_string)
-		
-		add_brackets ? "[#{s}]" : s
-	end
-end
-
-class Hash
-	def inspect_ordered(a=nil,b=nil)
-		"{"+keys.map{|x|x.to_s}.sort.map{|x|x.to_sym}.
-		map{|k| k.inspect + "=>"+self[k].inspect}.join(',')+"}"
-	end
-end
-
-module MaRuKu
-class MDElement	
-	def inspect(compact=true)
-		if compact
-			i2 = inspect2
-			return i2 if i2
-		end
-		
-		"md_el(:%s,%s,%s,%s)" %
-		[
-			self.node_type,
-			children_inspect(compact), 
-			@meta_priv.inspect_ordered,
-			self.al.inspect
-		]
-	end
-
-	def children_inspect(compact=true)
-		s = @children.inspect_more(compact,', ')
-		if @children.empty?
-			"[]"
-		elsif s.size < 70
-			s
-		else
-			"[\n"+
-			add_tabs(@children.inspect_more(compact,",\n",false))+
-			"\n]"
-		end
-	end
-	
-end
-
-end
-
diff --git a/lib/maruku/structures_iterators.rb b/lib/maruku/structures_iterators.rb
deleted file mode 100644
index ff9c6b4..0000000
--- a/lib/maruku/structures_iterators.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-module MaRuKu
-
-class MDElement
-	
-	# Yields to each element of specified node_type
-	# All elements if e_node_type is nil.
-	def each_element(e_node_type=nil, &block) 
-		@children.each do |c| 
-			if c.kind_of? MDElement
-				if (not e_node_type) || (e_node_type == c.node_type)
-					block.call c
-				end
-				c.each_element(e_node_type, &block)
-			end
-		end
-	end
-	
-	# Apply passed block to each String in the hierarchy.
-	def replace_each_string(&block)
-		for c in @children
-			if c.kind_of? MDElement
-				c.replace_each_string(&block)
-			end
-		end
-
-		processed = []
-		until @children.empty?
-			c = @children.shift
-			if c.kind_of? String
-				result = block.call(c)
-				[*result].each do |e| processed << e end
-			else
-				processed << c
-			end
-		end
-		@children = processed
-	end
-
-end
-end
\ No newline at end of file
diff --git a/lib/maruku/tests/benchmark.rb b/lib/maruku/tests/benchmark.rb
deleted file mode 100644
index 21d4a93..0000000
--- a/lib/maruku/tests/benchmark.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-require 'maruku'
-#require 'bluecloth'
-
-
-data = $stdin.read
-
-num = 10
-
-if ARGV.size > 0 && ((n=ARGV[0].to_i) != 0)
-	num = n
-end
-	
-methods = 
-[
-	
-	[Maruku,    :to_html],
-#	[BlueCloth, :to_html],
-	[Maruku,    :to_latex]
-	
-]
-
-#methods = [[Maruku, :class]]
-#num = 10
-
-stats = 
-methods .map do |c, method|
-	puts "Computing for #{c}"
-
-	start = Time.now
-	doc = nil
-	for i in 1..num
-		$stdout.write "#{i} "; $stdout.flush
-		doc = c.new(data)
-	end
-	stop = Time.now
-	parsing = (stop-start)/num
-
-	start = Time.now
-	for i in 1..num
-		$stdout.write "#{i} "; $stdout.flush
-		s = doc.send method
-	end
-	stop = Time.now
-	rendering = (stop-start)/num
-
-	puts ("%s (%s): parsing %0.2f sec + rendering %0.2f sec "+
-	"= %0.2f sec ") % [c, method, parsing,rendering,parsing+rendering]
-
-	[c, method, parsing, rendering]
-end
-
-puts "\n\n\n"
-stats.each do |x| x.push(x[2]+x[3]) end
-max = stats.map{|x|x[4]}.max
-stats.sort! { |x,y| x[4] <=> y[4] } . reverse!
-for c, method, parsing, rendering, tot in stats
-	puts ("%20s: parsing %0.2f sec + rendering %0.2f sec "+
-	"= %0.2f sec   (%0.2fx)") % 
-	["#{c} (#{method})", parsing,rendering,tot,max/tot]
-end
-
diff --git a/lib/maruku/tests/new_parser.rb b/lib/maruku/tests/new_parser.rb
deleted file mode 100644
index 8a01483..0000000
--- a/lib/maruku/tests/new_parser.rb
+++ /dev/null
@@ -1,373 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-require 'maruku'
-require 'maruku/ext/math'
-
-module MaRuKu; module Tests
-	# 5 accented letters in italian, encoded as UTF-8
-	AccIta8 = "\303\240\303\250\303\254\303\262\303\271"
-
-	# Same letters, written in ISO-8859-1 (one byte per letter)
-	AccIta1 = "\340\350\354\362\371"
-	
-	# The word MA-RU-KU, written in katakana using UTF-8
-	Maruku8 = "\343\203\236\343\203\253\343\202\257"
-	
-	def test_span_parser(verbose, break_on_first_error, quiet)
-	good_cases = [
-		
-		["",       [],         'Empty string gives empty list'],
-		["a",      ["a"],      'Easy char'],
-		[" a",     ["a"],      'First space in the paragraph is ignored'],
-		["a\n \n", ["a"],      'Last spaces in the paragraphs are ignored'],
-		[' ',      [],      'One char => nothing'],
-		['  ',     [],      'Two chars => nothing'],
-		['a  b',   ['a b'],    'Spaces are compressed'],
-		['a  b',   ['a b'],    'Newlines are spaces'],
-		["a\nb",   ['a b'],    'Newlines are spaces'],
-		["a\n b",  ['a b'],    'Compress newlines 1'],
-		["a \nb",  ['a b'],    'Compress newlines 2'],
-		[" \nb",   ['b'],      'Compress newlines 3'],
-		["\nb",    ['b'],      'Compress newlines 4'],
-		["b\n",    ['b'],     'Compress newlines 5'],
-		["\n",     [],      'Compress newlines 6'],
-		["\n\n\n", [],      'Compress newlines 7'],
-		
-		[nil, :throw, "Should throw on nil input"],
-		
-		# Code blocks
-		["`" ,   :throw,  'Unclosed single ticks'],
-		["``" ,  :throw,  'Unclosed double ticks'],
-		["`a`" ,     [md_code('a')],    'Simple inline code'],
-		["`` ` ``" ,    [md_code('`')],   ],
-		["`` \\` ``" ,    [md_code('\\`')],   ],
-		["``a``" ,   [md_code('a')],    ],
-		["`` a ``" ,   [md_code('a')],    ],
-		
-		# Newlines 
-		["a  \n", ['a',md_el(:linebreak)], 'Two spaces give br.'],
-		["a \n",  ['a'], 'Newlines 2'],
-		["  \n",  [md_el(:linebreak)], 'Newlines 3'],
-		["  \n  \n",  [md_el(:linebreak),md_el(:linebreak)],'Newlines 3'],
-		["  \na  \n",  [md_el(:linebreak),'a',md_el(:linebreak)],'Newlines 3'],
-		
-		# Inline HTML
-		["a < b", ['a < b'], '< can be on itself'],
-		["<hr>",  [md_html('<hr />')], 'HR will be sanitized'],
-		["<hr/>", [md_html('<hr />')], 'Closed tag is ok'],
-		["<hr  />", [md_html('<hr />')], 'Closed tag is ok 2'],
-		["<hr/>a", [md_html('<hr />'),'a'], 'Closed tag is ok 2'],
-		["<em></em>a", [md_html('<em></em>'),'a'], 'Inline HTML 1'],
-		["<em>e</em>a", [md_html('<em>e</em>'),'a'], 'Inline HTML 2'],
-		["a<em>e</em>b", ['a',md_html('<em>e</em>'),'b'], 'Inline HTML 3'],
-		["<em>e</em>a<em>f</em>", 
-			[md_html('<em>e</em>'),'a',md_html('<em>f</em>')], 
-			'Inline HTML 4'],
-		["<em>e</em><em>f</em>a", 
-			[md_html('<em>e</em>'),md_html('<em>f</em>'),'a'], 
-			'Inline HTML 5'],
-			
-			["<img src='a' />", [md_html("<img src='a' />")], 'Attributes'],
-			["<img src='a'/>"],
-		
-		# emphasis
-		["**", :throw, 'Unclosed double **'],
-		["\\*", ['*'], 'Escaping of *'],
-		["a *b* ", ['a ', md_em('b')], 'Emphasis 1'],
-		["a *b*", ['a ', md_em('b')], 'Emphasis 2'],
-		["a * b", ['a * b'], 'Emphasis 3'],
-		["a * b*", :throw, 'Unclosed emphasis'],
-		# same with underscore
-		["__", :throw, 'Unclosed double __'],
-		["\\_", ['_'], 'Escaping of _'],
-		["a _b_ ", ['a ', md_em('b')], 'Emphasis 4'],
-		["a _b_", ['a ', md_em('b')], 'Emphasis 5'],
-		["a _ b", ['a _ b'], 'Emphasis 6'],
-		["a _ b_", :throw, 'Unclosed emphasis'],
-		["_b_", [md_em('b')], 'Emphasis 7'],
-		["_b_ _c_", [md_em('b'),' ',md_em('c')], 'Emphasis 8'],
-		["_b__c_", [md_em('b'),md_em('c')], 'Emphasis 9'],
-		# underscores in word
-		["mod_ruby", ['mod_ruby'], 'Word with underscore'],
-		# strong
-		["**a*", :throw, 'Unclosed double ** 2'],
-		["\\**a*", ['*', md_em('a')], 'Escaping of *'],
-		["a **b** ", ['a ', md_strong('b')], 'Emphasis 1'],
-		["a **b**", ['a ', md_strong('b')], 'Emphasis 2'],
-		["a ** b", ['a ** b'], 'Emphasis 3'],
-		["a ** b**", :throw, 'Unclosed emphasis'],
-		["**b****c**", [md_strong('b'),md_strong('c')], 'Emphasis 9'],
-		# strong (with underscore)
-		["__a_", :throw, 'Unclosed double __ 2'],
-	
-	#	["\\__a_", ['_', md_em('a')], 'Escaping of _'],
-		["a __b__ ", ['a ', md_strong('b')], 'Emphasis 1'],
-		["a __b__", ['a ', md_strong('b')], 'Emphasis 2'],
-		["a __ b", ['a __ b'], 'Emphasis 3'],
-		["a __ b__", :throw, 'Unclosed emphasis'],
-		["__b____c__", [md_strong('b'),md_strong('c')], 'Emphasis 9'],
-		# extra strong
-		["***a**", :throw, 'Unclosed triple *** '],
-		["\\***a**", ['*', md_strong('a')], 'Escaping of *'],
-		["a ***b*** ", ['a ', md_emstrong('b')], 'Strong elements'],
-		["a ***b***", ['a ', md_emstrong('b')]],
-		["a *** b", ['a *** b']],
-		["a ** * b", ['a ** * b']],
-		["***b******c***", [md_emstrong('b'),md_emstrong('c')]],
-		["a *** b***", :throw, 'Unclosed emphasis'],
-		# same with underscores
-		["___a__", :throw, 'Unclosed triple *** '],
-#		["\\___a__", ['_', md_strong('a')], 'Escaping of _'],
-		["a ___b___ ", ['a ', md_emstrong('b')], 'Strong elements'],
-		["a ___b___", ['a ', md_emstrong('b')]],
-		["a ___ b", ['a ___ b']],
-		["a __ _ b", ['a __ _ b']],
-		["___b______c___", [md_emstrong('b'),md_emstrong('c')]],
-		["a ___ b___", :throw, 'Unclosed emphasis'],
-		# mixing is bad
-		["*a_", :throw, 'Mixing is bad'],
-		["_a*", :throw],
-		["**a__", :throw],
-		["__a**", :throw],
-		["___a***", :throw],
-		["***a___", :throw],
-		# links of the form [text][ref]
-		["\\[a]",  ["[a]"], 'Escaping 1'],
-		["\\[a\\]", ["[a]"], 'Escaping 2'],
-# This is valid in the new Markdown version
-#		["[a]",   ["a"],   'Not a link'],
-		["[a]",   [ md_link(["a"],'a')], 'Empty link'],
-		["[a][]", ],
-		["[a][]b",   [ md_link(["a"],'a'),'b'], 'Empty link'],
-		["[a\\]][]", [ md_link(["a]"],'a')], 'Escape inside link (throw ?] away)'],
-		
-		["[a",  :throw,   'Link not closed'],
-		["[a][",  :throw,   'Ref not closed'],
-		
-		# links of the form [text](url)
-		["\\[a](b)",  ["[a](b)"], 'Links'],
-		["[a](url)c",  [md_im_link(['a'],'url'),'c'], 'url'],
-		["[a]( url )c" ],
-		["[a] (	url )c" ],
-		["[a] (	url)c" ],
-		
-		["[a](ur:/l/ 'Title')",  [md_im_link(['a'],'ur:/l/','Title')],
-		 	'url and title'],
-		["[a] (	ur:/l/ \"Title\")" ],
-		["[a] (	ur:/l/ \"Title\")" ],
-		["[a]( ur:/l/ Title)", :throw, "Must quote title" ],
-
-		["[a](url 'Tit\\\"l\\\\e')", [md_im_link(['a'],'url','Tit"l\\e')],
-		 	'url and title escaped'],
-		["[a] (	url \"Tit\\\"l\\\\e\")" ],
-		["[a] (	url	\"Tit\\\"l\\\\e\"  )" ],
-		['[a] (	url	"Tit\\"l\\\\e"  )' ],
-		["[a]()", [md_im_link(['a'],'')], 'No URL is OK'],
-	
-		["[a](\"Title\")", :throw, "No url specified" ],
-		["[a](url \"Title)", :throw, "Unclosed quotes" ],
-		["[a](url \"Title\\\")", :throw],
-		["[a](url \"Title\" ", :throw],
-
-		["[a](url \'Title\")", :throw, "Mixing is bad" ],
-		["[a](url \"Title\')"],
-		
-		["[a](/url)", [md_im_link(['a'],'/url')], 'Funny chars in url'],
-		["[a](#url)", [md_im_link(['a'],'#url')]],
-		["[a](</script?foo=1&bar=2>)", [md_im_link(['a'],'/script?foo=1&bar=2')]],
-		
-		
-		# Images
-		["\\![a](url)",  ['!', md_im_link(['a'],'url') ], 'Escaping images'],
-		
-		["![a](url)",  [md_im_image(['a'],'url')], 'Image no title'],
-		["![a]( url )" ],
-		["![a] (	url )" ],
-		["![a] (	url)" ],
-
-		["![a](url 'ti\"tle')",  [md_im_image(['a'],'url','ti"tle')], 'Image with title'],
-		['![a]( url "ti\\"tle")' ],
-
-		["![a](url", :throw, 'Invalid images'],
-		["![a( url )" ],
-		["![a] ('url )" ],
-
-		["![a][imref]",  [md_image(['a'],'imref')], 'Image with ref'],
-		["![a][ imref]"],
-		["![a][ imref ]"],
-		["![a][\timref\t]"],
-		
-
-		['<http://example.com/?foo=1&bar=2>', 
-			[md_url('http://example.com/?foo=1&bar=2')], 'Immediate link'],
-			['a<http://example.com/?foo=1&bar=2>b', 
-				['a',md_url('http://example.com/?foo=1&bar=2'),'b']  ],
-		['<andrea at censi.org>', 
-			[md_email('andrea at censi.org')], 'Email address'],
-		['<mailto:andrea at censi.org>'],
-		["Developmen <http://rubyforge.org/projects/maruku/>",
-			 ["Developmen ", md_url("http://rubyforge.org/projects/maruku/")]],
-		["a<!-- -->b", ['a',md_html('<!-- -->'),'b'], 
-			'HTML Comment'],
-
-		["a<!--", :throw, 'Bad HTML Comment'],
-		["a<!-- ", :throw, 'Bad HTML Comment'],
-
-		["<?xml <?!--!`3  ?>", [md_xml_instr('xml','<?!--!`3')], 'XML processing instruction'],
-		["<? <?!--!`3  ?>", [md_xml_instr('','<?!--!`3')] ],
-
-		["<? ", :throw, 'Bad Server directive'],
-
-		["a <b", :throw, 'Bad HTML 1'],
-		["<b",   :throw, 'Bad HTML 2'],
-		["<b!",  :throw, 'Bad HTML 3'],
-		['`<div>`, `<table>`, `<pre>`, `<p>`',
-			[md_code('<div>'),', ',md_code('<table>'),', ',
-				md_code('<pre>'),', ',md_code('<p>')],
-				'Multiple HTLM tags'],
-				
-		["&andrea", ["&andrea"], 'Parsing of entities'],
-# no escaping is allowed
-#			["\\&andrea;", ["&andrea;"]],
-		["l&andrea;", ["l", md_entity('andrea')] ],
-		["&&andrea;", ["&", md_entity('andrea')] ],
-		["&123;;&",[md_entity('123'),';',md_entity('amp')]],
-		
-		["a\nThe [syntax page] [s] provides", 
-			['a The ', md_link(['syntax page'],'s'), ' provides'], 'Regression'],
-		
-		['![a](url "ti"tle")', [md_im_image(['a'],'url','ti"tle')], 
-			"Image with quotes"],
-		['![a](url \'ti"tle\')' ],
-		
-		['[bar](/url/ "Title with "quotes" inside")', 
-			[md_im_link(["bar"],'/url/', 'Title with "quotes" inside')],
-			"Link with quotes"],
-
-# We dropped this idea		
-#		['$20,000 and $30,000', ['$20,000 and $30,000'], 'Math: spaces'],
-		['$20,000$', [md_inline_math('20,000')]],
-#		['$ 20,000$', ['$ 20,000$']],
-#		['$20,000 $ $20,000$', ['$20,000 $ ', md_inline_math('20,000')]],
-		["#{Maruku8}", [Maruku8], "Reading UTF-8"],
-#		["#{AccIta1}", [AccIta8], "Converting ISO-8859-1 to UTF-8", 
-#			{:encoding => 'iso-8859-1'}],
-						
-	]
-
-		good_cases = unit_tests_for_attribute_lists + good_cases
-		
-		count = 1; last_comment=""; last_expected=:throw
-		good_cases.each do |t|
-			if not t[1]
-				t[1] = last_expected
-			else
-				last_expected = t[1]
-			end				
-			if not t[2]
-				t[2] = last_comment + " #{count+=1}"
-			else
-				last_comment = t[2]; count=1
-			end
-		end
-		
-		
-			
-		@verbose = verbose
-		m = Maruku.new
-		m.attributes[:on_error] = :raise
-		Globals[:debug_keep_ials] = true
-		
-		num_ok = 0
-		good_cases.each do |input, expected, comment|
-				output = nil
-				begin
-					output = m.parse_span_better(input)
-					#lines = Maruku.split_lines input
-					#output = m.parse_lines_as_span(lines)
-				rescue Exception => e
-					if not expected == :throw
-						ex = e.inspect+ "\n"+ e.backtrace.join("\n")
-						s = comment+describe_difference(input, expected, output)
-							
-						print_status(comment,'CRASHED :-(', ex+s)
-						raise e if @break_on_first_error 
-					else
-						quiet || print_status(comment,'OK')
-						num_ok += 1
-					end
-				end
-				
-				if not expected == :throw
-					if not (expected == output)
-						s = comment+describe_difference(input, expected, output)
-						print_status(comment, 'FAILED', s)
-						break if break_on_first_error
-					else
-						num_ok += 1
-						quiet || print_status(comment, 'OK')
-					end
-				else # I expected a raise
-					if output
-						s = comment+describe_difference(input, expected, output)
-						
-						print_status(comment, 'FAILED (no throw)', s)
-						break if break_on_first_error
-					end
-				end		
-		end  # do 
-		if num_ok != good_cases.size
-			return false
-		else
-			return true
-		end
-	end
-	
-	PAD=40
-	def print_status(comment, status, verbose_text=nil)
-		if comment.size < PAD
-			comment = comment + (" "*(PAD-comment.size))
-		end
-		puts "- #{comment} #{status}"
-		if @verbose and verbose_text
-			puts verbose_text
-		end
-	end
-	
-	
-	def describe_difference(input, expected, output)
-		"\nInput:\n  #{input.inspect}" +
-		    "\nExpected:\n  #{expected.inspect}" +
-			"\nOutput:\n  #{output.inspect}\n"
-	end
-end end
-
-class Maruku
-	include MaRuKu::Tests
-end
-
-verbose = ARGV.include? 'v'
-break_on_first = ARGV.include? 'b'
-quiet = ARGV.include? 'q'
-ok = Maruku.new.test_span_parser(verbose, break_on_first, quiet)
-
-exit (ok ? 0 : 1)
diff --git a/lib/maruku/tests/tests.rb b/lib/maruku/tests/tests.rb
deleted file mode 100644
index 6ecf926..0000000
--- a/lib/maruku/tests/tests.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
-
-require 'maruku'
-
-class Maruku
-	
-	
-	def Maruku.failed(test, doc, s)
-		raise "Test failed: #{s}\n*****\n#{test}\n*****\n"+
-		"#{doc.inspect}\n*****\n{doc.to_html}"
-	end
-
-	def Maruku.metaTests
-		ref = {:id => 'id1', :class => ['class1','class2'], 
-			:style=> 'Style is : important = for all } things'}
-	
-		
-		tests = MetaTests.split('***')
-		for test in tests
-			#puts "Test: #{test.inspect}"
-			doc = Maruku.new(test)
-			
-			doc.children.size == 1 ||
-			failed(test, doc, "children != 1") 
-				
-			
-			h = doc.children[0]
-			
-			h.node_type==:header ||
-			failed(test, doc, "child not header") 
-			
-#			puts doc.inspect
-#			puts doc.to_html
-		end
-	end
-	
-MetaTests = <<EOF
-
-# Head # {ref1 ref2 ref3}
-
-{ref1}: id: id1; class: class1
-{ref2}: class: class2
-{ref3}: style: "Style is : important = for all } things"  
-
-***
-
-# Head # {ref1 ref3 ref2}
-
-{ref1}: id: id1; class: class1
-{ref2}: class: class2
-{ref3}: style: "Style is : important = for all } things"  
-
-***
-
-# Head # {ref1 ref2 ref3}
-
-{ref1}: id= id1; class=class1
-{ref2}: class=class2
-{ref3}: style="Style is : important = for all } things"
-
-***
-
-# Head # {ref1 ref2 ref3}
-
-{ref1}: id=id1 class=class1
-{ref2}: class=class2
-{ref3}: style="Style is : important = for all } things"
-
-***
-# Head # {ref1 ref2 ref3}
-
-{ref1}: id:id1	class:class1
-{ref2}: class : class2
-{ref3}: style	=	"Style is : important = for all } things"
-
-***
-# Head # {ref1 ref2 ref3}
-
-{ref1}: id:id1	class:class1
-  {ref2}: class : class2
-   {ref3}: style	=	"Style is : important = for all } things"
-
-***
-
-# Head # {#id1 .class1 ref2 ref3}
-
-{ref2}: class : class2
-{ref3}: style	=	"Style is : important = for all } things"
-
-***
-
-# Head #  	 {  #id1	.class1	 	ref2	  ref3	}
-
-{ref2}: class : class2
-{ref3}: style	=	"Style is : important = for all } things"
-
-***
-
-# Head #  	 {  id=id1	class=class1	 	ref2	  ref3	}
-
-{ref2}: class : class2
-{ref3}: style	=	"Style is : important = for all } things"
-
-***
-
-# Head #  	 {  id:id1	class="class1" class:"class2"  style="Style is : important = for all } things"}
-
-EOF
-
-end
-
-if File.basename($0) == 'tests.rb'
-	Maruku.metaTests
-	
-end
-
-
diff --git a/lib/maruku/toc.rb b/lib/maruku/toc.rb
index fc717bf..d4caf86 100644
--- a/lib/maruku/toc.rb
+++ b/lib/maruku/toc.rb
@@ -1,199 +1,188 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
+module MaRuKu
+  # A section in the table of contents of a document.
+  class Section
+    # The depth of the section (0 for toplevel).
+    #
+    # Equivalent to `header_element.level`.
+    #
+    # @return [Fixnum]
+    attr_accessor :section_level
 
+    # The nested section number, e.g. `[1, 2, 5]` for Section 1.2.5.
+    #
+    # @return [Array<Fixnum>]
+    attr_accessor :section_number
 
-module MaRuKu
-	
-class MDDocument
-	# an instance of Section (see below)
-	attr_accessor :toc 
-end
+    # The `:header` node for this section.
+    # The value of `meta[:section]` for the header will be this node.
+    #
+    # @return [MDElement]
+    attr_accessor :header_element
+
+    # The immediate child nodes of this section.
+    #
+    # @todo Why does this never contain Strings?
+    #
+    # @return [Array<MDElement>]
+    attr_accessor :immediate_children
+
+    # The subsections of this section.
+    #
+    # @return [Array<Section>]
+    attr_accessor :section_children
+
+    def initialize
+      @immediate_children = []
+      @section_children = []
+    end
+
+    def inspect(indent = 1)
+      if @header_element
+        s = "\_" * indent <<
+          "(#{@section_level})>\t #{@section_number.join('.')} : " <<
+          @header_element.children_to_s <<
+          " (id: '#{@header_element.attributes[:id]}')\n"
+      else
+        s = "Master\n"
+      end
+      @section_children.each {|c| s << c.inspect(indent + 1) }
+
+      s
+    end
+
+    # Assign \{#section\_number section numbers}
+    # to this section and its children.
+    # This also assigns the section number attribute
+    # to the sections' headers.
+    #
+    # This should only be called on the root section.
+    #
+    # @overload def numerate
+    def numerate(a = [])
+      self.section_number = a
+      self.section_children.each_with_index {|c, i| c.numerate(a + [i + 1])}
+      if h = self.header_element
+        h.attributes[:section_number] = self.section_number
+      end
+    end
+
+
+    # Returns an HTML representation of the table of contents.
+    #
+    # This should only be called on the root section.
+    def to_html
+      MaRuKu::Out::HTML::HTMLElement.new('div', { 'class' => 'maruku_toc' }, _to_html)
+    end
+
+    # Returns a LaTeX representation of the table of contents.
+    #
+    # This should only be called on the root section.
+    def to_latex
+      _to_latex + "\n\n"
+    end
+
+    protected
+
+    def _to_html
+      ul = MaRuKu::Out::HTML::HTMLElement.new('ul')
+      @section_children.each do |c|
+        li = MaRuKu::Out::HTML::HTMLElement.new('li')
+        if span = c.header_element.render_section_number
+          li << span
+        end
 
-	# This represents a section in the TOC.
-	class Section
-		# a Fixnum, is == header_element.level
-		attr_accessor :section_level 
-		
-		# An array of fixnum, like [1,2,5] for Section 1.2.5
-		attr_accessor :section_number 
-		
-		# reference to header (header has h.meta[:section] to self)
-		attr_accessor :header_element
-
-		# Array of immediate children of this element
-		attr_accessor :immediate_children
-		
-		# Array of Section inside this section
-		attr_accessor :section_children
-		
-		def initialize
-			@immediate_children = []
-			@section_children = []
-		end
-	end 
-
-	class Section
-		def inspect(indent=1)
-			s = ""
-			if @header_element
-				s +=  "\_"*indent +  "(#{@section_level})>\t #{@section_number.join('.')} : "
-				s +=  @header_element.children_to_s +
-				 " (id: '#{@header_element.attributes[:id]}')\n"
-			else
-				s += "Master\n"
-			end
-			
-			@section_children.each do |c|
-				s+=c.inspect(indent+1)
-			end
-			s
-		end
-		
-		# Numerate this section and its children
-		def numerate(a=[])
-			self.section_number = a
-			section_children.each_with_index do |c,i|
-				c.numerate(a.clone.push(i+1))
-			end
-			if h = self.header_element
-				h.attributes[:section_number] = self.section_number
-			end
-		end
-		
-		include REXML
-		# Creates an HTML toc.
-		# Call this on the root 
-		def to_html
-			div = Element.new 'div'
-			div.attributes['class'] = 'maruku_toc'
-			div << create_toc
-			div
-		end
-		
-		def create_toc
-			ul = Element.new 'ul'
-			# let's remove the bullets
-			ul.attributes['style'] = 'list-style: none;' 
-			@section_children.each do |c|
-				li = Element.new 'li'
-				if span = c.header_element.render_section_number
-					li << span
-				end
-				a = c.header_element.wrap_as_element('a')
-					a.delete_attribute 'id'
-					a.attributes['href'] = "##{c.header_element.attributes[:id]}"
-				li << a
-				li << c.create_toc if c.section_children.size>0
-				ul << li
-			end
-			ul
-		end
-
-		# Creates a latex toc.
-		# Call this on the root 
-		def to_latex
-			to_latex_rec + "\n\n"
-		end
-		
-		def to_latex_rec
-			s = ""
-			@section_children.each do |c|
-				s += "\\noindent"
-				number = c.header_element.section_number
-				s += number if number
-					text = c.header_element.children_to_latex
-					id = c.header_element.attributes[:id]
-				s += "\\hyperlink{#{id}}{#{text}}"
-				s += "\\dotfill \\pageref*{#{id}} \\linebreak\n"
-				s += c.to_latex_rec  if c.section_children.size>0
-
-			end
-			s
-		end
-		
-	end
-
-	class MDDocument
-	
-		def create_toc
-			each_element(:header) do |h|
-				h.attributes[:id] ||= h.generate_id
-			end
-		
-			stack = []
-		
-			# the ancestor section
-			s = Section.new
-			s.section_level = 0
-
-			stack.push s
-	
-			i = 0;
-			while i < @children.size
-				while i < @children.size 
-					if @children[i].node_type == :header
-						level = @children[i].level
-						break if level <= stack.last.section_level+1
-					end
-				
-					stack.last.immediate_children.push @children[i]
-					i += 1
-				end
-
-				break if i>=@children.size
-			
-				header = @children[i]
-				level = header.level
-			
-				if level > stack.last.section_level
-					# this level is inside
-				
-					s2 = Section.new
-					s2.section_level = level
-					s2.header_element = header
-					header.instance_variable_set :@section, s2
-				
-					stack.last.section_children.push s2
-					stack.push s2
-				
-					i+=1
-				elsif level == stack.last.section_level
-					# this level is a sibling
-					stack.pop
-				else 
-					# this level is a parent
-					stack.pop
-				end
-			
-			end
-
-			# If there is only one big header, then assume
-			# it is the master
-			if s.section_children.size == 1
-				s = s.section_children.first
-			end
-		
-			# Assign section numbers
-			s.numerate
-	
-			s
-		end
-	end
-end
\ No newline at end of file
+        a = c.header_element.wrap_as_element('a')
+        a.attributes.delete('id')
+        a['href'] = "##{c.header_element.attributes[:id]}"
+
+        li << a
+        li << c._to_html if c.section_children.size > 0
+        ul << li
+      end
+      ul
+    end
+
+    def _to_latex
+      s = ""
+      @section_children.each do |c|
+        s << "\\noindent"
+        if number = c.header_element.section_number
+          s << number
+        end
+        id = c.header_element.attributes[:id]
+        text = c.header_element.children_to_latex
+        s << "\\hyperlink{#{id}}{#{text}}"
+        s << "\\dotfill \\pageref*{#{id}} \\linebreak\n"
+        s << c._to_latex if c.section_children.size > 0
+      end
+      s
+    end
+  end
+
+  class MDDocument
+    # The table of contents for the document.
+    #
+    # @return [Section]
+    attr_accessor :toc
+
+    # A map of header IDs to a count of how many times they've occurred in the document.
+    #
+    # @return [Hash<String, Number>]
+    attr_accessor :header_ids
+    
+    def create_toc
+      self.header_ids = Hash.new(0)
+
+      each_element(:header) {|h| h.attributes[:id] ||= h.generate_id }
+
+
+      # The root section
+      s = Section.new
+      s.section_level = 0
+
+      stack = [s]
+
+      i = 0
+      while i < @children.size
+        if children[i].node_type == :header
+          header = @children[i]
+          level = header.level
+          s2 = Section.new
+          s2.section_level = level
+          s2.header_element = header
+          header.instance_variable_set :@section, s2
+          while level <= stack.last.section_level
+            stack.pop
+          end
+          stack.last.section_children.push s2
+          stack.push s2
+        else
+          stack.last.immediate_children.push @children[i]
+        end
+        i += 1
+      end
+
+      # If there is only one big header, then assume
+      # it is the master
+      if s.section_children.size == 1
+        s = s.section_children.first
+      end
+
+      # Assign section numbers
+      s.numerate
+
+      s
+    end
+  end
+
+  class MDElement
+    # Generate an id for headers. Assumes @children is set.
+    def generate_id
+      raise "generate_id only makes sense for headers" unless node_type == :header
+      generated_id = children_to_s.tr(' ', '_').downcase.gsub(/\W/, '').strip
+      num_occurs = (@doc.header_ids[generated_id] += 1)
+      generated_id += "_#{num_occurs}" if num_occurs > 1
+      generated_id
+    end
+  end
+end
diff --git a/lib/maruku/usage/example1.rb b/lib/maruku/usage/example1.rb
deleted file mode 100644
index 2c20a6f..0000000
--- a/lib/maruku/usage/example1.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'maruku'
-
-text = <<EOF
-Chapter 1
-=========
-
-It was a stormy and rainy night.
-
-EOF
-
-invalid = <<EOF
-
-This is a [bad link.
-
-EOF
-
-Maruku.new(text).to_html
-
-s = ""
-
-begin 
-	Maruku.new(invalid, {:on_error => :raise, :error_stream => s})
-	puts "Error! It should have thrown an exception."
-rescue
-	# puts "ok, got error"
-end
-
-begin 
-	Maruku.new(invalid, {:on_error => :warning, :error_stream => s})
-rescue
-	puts "Error! It should not have thrown an exception."
-end
-
diff --git a/lib/maruku/version.rb b/lib/maruku/version.rb
index 905b179..86a7984 100644
--- a/lib/maruku/version.rb
+++ b/lib/maruku/version.rb
@@ -1,40 +1,35 @@
-#--
-#   Copyright (C) 2006  Andrea Censi  <andrea (at) rubyforge.org>
-#
-# This file is part of Maruku.
-# 
-#   Maruku is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-# 
-#   Maruku is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-# 
-#   You should have received a copy of the GNU General Public License
-#   along with Maruku; if not, write to the Free Software
-#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-#++
-
 module MaRuKu
-	Version = '0.6.0'
-	
-	MarukuURL = 'http://maruku.rubyforge.org/'
-	
-	# If true, use also PHP Markdown extra syntax
-	#
-	# Note: it is not guaranteed that if it's false
-	# then no special features will be used.
-	#
-	# So please, ignore it for now.
-	def markdown_extra?
-		true
-	end
-	
-	def new_meta_data?
-		true
-	end
-	
+  # The Maruku version.
+  VERSION = '0.7.1'
+
+  # @deprecated Exists for backwards compatibility. Use {VERSION}
+  # @private
+  Version = VERSION
+
+  # The URL of the Maruku website.
+  MARUKU_URL = 'http://github.com/bhollis/maruku/'
+
+  # @deprecated Exists for backwards compatibility. Use {MARUKU_URL}
+  # @private
+  MarukuURL = MARUKU_URL
+
+  # Whether Markdown implements the PHP Markdown extra syntax.
+  #
+  # Note: it is not guaranteed that if this is false,
+  # then no special features will be used.
+  #
+  # @return [Boolean]
+  def markdown_extra?
+    true
+  end
+
+  # Whether Markdown implements the new meta-data proposal.
+  #
+  # Note: it is not guaranteed that if this is false,
+  # then no special features will be used.
+  #
+  # @return [Boolean]
+  def new_meta_data?
+    true
+  end
 end
diff --git a/maruku_gem.rb b/maruku_gem.rb
deleted file mode 100644
index f4ae0c7..0000000
--- a/maruku_gem.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-
-require 'lib/maruku/version'
-
-$spec = Gem::Specification.new do |s|
-  s.name = 'maruku'
-  s.version = MaRuKu::Version
-  s.summary = "Maruku is a Markdown-superset interpreter written in Ruby."
-  s.description = %{Maruku is a Markdown interpreter in Ruby.
-	It features native export to HTML and PDF (via Latex). The
-	output is really beautiful!
-	}
-  s.files = Dir['lib/**/*.rb'] + Dir['lib/*.rb'] + 
-	Dir['docs/*.md'] +	Dir['docs/*.html'] +
-	Dir['tests/**/*.md'] +
-          Dir['bin/*'] + Dir['*.sh'] + ['Rakefile', 'maruku_gem.rb']
-
-  s.bindir = 'bin'
-  s.executables = ['maruku','marutex']
-
-  s.require_path = 'lib'
-  s.autorequire = 'maruku'
-
-  s.add_dependency('syntax', '>= 1.0.0')
-
-  s.author = "Andrea Censi"
-  s.email = "andrea at rubyforge.org"
-  s.homepage = "http://maruku.rubyforge.org"
-end
-
-#  s.has_rdoc = true
-#  s.extra_rdoc_files = Dir['[A-Z]*']
-#  s.rdoc_options << '--title' <<  'Builder -- Easy XML Building'
-
diff --git a/metadata.gz.sig b/metadata.gz.sig
new file mode 100644
index 0000000..dbbd9ea
--- /dev/null
+++ b/metadata.gz.sig
@@ -0,0 +1,3 @@
+M�۔�$
+�����z봓�{Z&j^+A�u���9+�^w:���K������
��A\�d]��(�V��ӗ��|{��)
��{�Lh�pm������[��&*
1����A�£|�)R�uOI�
 �G�
+�T����{�dz*�i�ܷL��V�]$Yϰ����7G�NJB9���U+�c����4�2_�si�3��C��[o[z�ɯ&�EM�%�5N��UX��M��
,
��^1
\ No newline at end of file
diff --git a/metadata.yml b/metadata.yml
index 3101a85..dfeaebf 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,42 +1,69 @@
---- !ruby/object:Gem::Specification 
+--- !ruby/object:Gem::Specification
 name: maruku
-version: !ruby/object:Gem::Version 
-  version: 0.6.0
+version: !ruby/object:Gem::Version
+  version: 0.7.1
 platform: ruby
-authors: 
+authors:
 - Andrea Censi
-autorequire: maruku
+- Nathan Weizenbaum
+- Ben Hollis
+autorequire: 
 bindir: bin
-cert_chain: []
-
-date: 2009-05-04 00:00:00 -07:00
-default_executable: 
-dependencies: 
-- !ruby/object:Gem::Dependency 
-  name: syntax
-  version_requirement: 
-  version_requirements: !ruby/object:Gem::Requirement 
-    requirements: 
-    - - ">="
-      - !ruby/object:Gem::Version 
-        version: 1.0.0
-    version: 
-description: Maruku is a Markdown interpreter in Ruby. It features native export to HTML and PDF (via Latex). The output is really beautiful!
-email: andrea at rubyforge.org
-executables: 
+cert_chain:
+- |
+  -----BEGIN CERTIFICATE-----
+  MIIDbDCCAlSgAwIBAgIBATANBgkqhkiG9w0BAQUFADA+MQwwCgYDVQQDDANiZW4x
+  GTAXBgoJkiaJk/IsZAEZFgliZW5ob2xsaXMxEzARBgoJkiaJk/IsZAEZFgNuZXQw
+  HhcNMTMwMzExMDI1NTUzWhcNMTQwMzExMDI1NTUzWjA+MQwwCgYDVQQDDANiZW4x
+  GTAXBgoJkiaJk/IsZAEZFgliZW5ob2xsaXMxEzARBgoJkiaJk/IsZAEZFgNuZXQw
+  ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5zj8rp/43ROFWTrOmaXFI
+  saYRkgYgv5y0+10/MRZDPYT3i42GRmCPRd+ZWAVPKGJCRgSizgAfPSYh8+CFceFm
+  ZVzeTd5haVWgsSkLpDHc3CuIUnanEOhlLcNt7bjofoxiZaqMm8ntLGAPARunOn4H
+  whN7a82KEMRYCqC0H1TvTR15K7Fb40U6UgrqwiaQtDvTyIALakzICl2mBk5we3La
+  OAgoKVT0SDAUa8E4BSitpOpukNTPPy7r0WKb8yO69ON19LGxg17tDJjolKYsScOt
+  +nXZj7HJwfBkn9m6zxDqCk7mvAvybH7oMOCzrxLB9kxSOjNOCVnOV26Bj5xPUY8p
+  AgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBTXpLoI
+  loLWXfgQPVg/t4cAuHJZeDAcBgNVHREEFTATgRFiZW5AYmVuaG9sbGlzLm5ldDAc
+  BgNVHRIEFTATgRFiZW5AYmVuaG9sbGlzLm5ldDANBgkqhkiG9w0BAQUFAAOCAQEA
+  CYVy5TtuDMQz7ddO+bc+Jve9V6o1Fpu6bXTlwsXafXtfOeJ3/+0g+WboTCbCWjIR
+  JnPcE2vCVrLF48PpR3YWVRGZai4YxRXdmZEcVDnJReymUHVu0hZdcxV6+LecoZ5a
+  X06W7WI+JhEKb5zIgGFGuW074n0el0il85NI/frb9D3dOKqU5+NK7hrRO8rjWLXo
+  U+KBnqpu0lI1TIAshS1R8JYVLIixEg6sl3+QljvpDQW+P4D1qg6wspdjKj91/geA
+  KwEyUbH6HjXBdbfv95jHa8ncuWqIryt/ywGZg3sbPVsscZA9RcyDtUQRnlHSGRWH
+  ZSsIzVZvxIwTYa0z3d+JWQ==
+  -----END CERTIFICATE-----
+date: 2014-01-15 00:00:00.000000000 Z
+dependencies: []
+description: "Maruku is a Markdown interpreter in Ruby.\n\tIt features native export
+  to HTML and PDF (via Latex). The\n\toutput is really beautiful!"
+email: ben at benhollis.net
+executables:
 - maruku
 - marutex
 extensions: []
-
 extra_rdoc_files: []
-
-files: 
+files:
+- MIT-LICENSE.txt
+- bin/maruku
+- bin/marutex
+- data/entities.xml
+- docs/div_syntax.md
+- docs/entity_test.md
+- docs/markdown_syntax.md
+- docs/maruku.md
+- docs/math.md
+- docs/other_stuff.md
+- docs/proposal.md
+- lib/maruku.rb
 - lib/maruku/attributes.rb
 - lib/maruku/defaults.rb
-- lib/maruku/errors_management.rb
+- lib/maruku/document.rb
+- lib/maruku/element.rb
+- lib/maruku/errors.rb
 - lib/maruku/ext/div.rb
+- lib/maruku/ext/fenced_code.rb
+- lib/maruku/ext/math.rb
 - lib/maruku/ext/math/elements.rb
-- lib/maruku/ext/math/latex_fix.rb
 - lib/maruku/ext/math/mathml_engines/blahtex.rb
 - lib/maruku/ext/math/mathml_engines/itex2mml.rb
 - lib/maruku/ext/math/mathml_engines/none.rb
@@ -44,208 +71,210 @@ files:
 - lib/maruku/ext/math/parsing.rb
 - lib/maruku/ext/math/to_html.rb
 - lib/maruku/ext/math/to_latex.rb
-- lib/maruku/ext/math.rb
 - lib/maruku/helpers.rb
+- lib/maruku/html.rb
 - lib/maruku/input/charsource.rb
 - lib/maruku/input/extensions.rb
 - lib/maruku/input/html_helper.rb
 - lib/maruku/input/linesource.rb
+- lib/maruku/input/mdline.rb
 - lib/maruku/input/parse_block.rb
 - lib/maruku/input/parse_doc.rb
-- lib/maruku/input/parse_span_better.rb
+- lib/maruku/input/parse_span.rb
 - lib/maruku/input/rubypants.rb
-- lib/maruku/input/type_detection.rb
 - lib/maruku/input_textile2/t2_parser.rb
+- lib/maruku/inspect_element.rb
 - lib/maruku/maruku.rb
+- lib/maruku/output/entity_table.rb
 - lib/maruku/output/s5/fancy.rb
 - lib/maruku/output/s5/to_s5.rb
 - lib/maruku/output/to_html.rb
 - lib/maruku/output/to_latex.rb
-- lib/maruku/output/to_latex_entities.rb
-- lib/maruku/output/to_latex_strings.rb
 - lib/maruku/output/to_markdown.rb
 - lib/maruku/output/to_s.rb
 - lib/maruku/string_utils.rb
-- lib/maruku/structures.rb
-- lib/maruku/structures_inspect.rb
-- lib/maruku/structures_iterators.rb
-- lib/maruku/tests/benchmark.rb
-- lib/maruku/tests/new_parser.rb
-- lib/maruku/tests/tests.rb
 - lib/maruku/textile2.rb
 - lib/maruku/toc.rb
-- lib/maruku/usage/example1.rb
 - lib/maruku/version.rb
-- lib/maruku.rb
-- docs/changelog.md
-- docs/div_syntax.md
-- docs/entity_test.md
-- docs/markdown_syntax.md
-- docs/maruku.md
-- docs/math.md
-- docs/other_stuff.md
-- docs/proposal.md
-- tests/bugs/code_in_links.md
-- tests/bugs/complex_escaping.md
-- tests/math/syntax.md
-- tests/math_usage/document.md
-- tests/others/abbreviations.md
-- tests/others/blank.md
-- tests/others/code.md
-- tests/others/code2.md
-- tests/others/code3.md
-- tests/others/email.md
-- tests/others/entities.md
-- tests/others/escaping.md
-- tests/others/extra_dl.md
-- tests/others/extra_header_id.md
-- tests/others/extra_table1.md
-- tests/others/footnotes.md
-- tests/others/headers.md
-- tests/others/hrule.md
-- tests/others/images.md
-- tests/others/inline_html.md
-- tests/others/links.md
-- tests/others/list1.md
-- tests/others/list2.md
-- tests/others/list3.md
-- tests/others/lists.md
-- tests/others/lists_after_paragraph.md
-- tests/others/lists_ol.md
-- tests/others/misc_sw.md
-- tests/others/one.md
-- tests/others/paragraphs.md
-- tests/others/sss06.md
-- tests/others/test.md
-- tests/s5/s5profiling.md
-- tests/unittest/abbreviations.md
-- tests/unittest/alt.md
-- tests/unittest/attributes/att2.md
-- tests/unittest/attributes/att3.md
-- tests/unittest/attributes/attributes.md
-- tests/unittest/attributes/circular.md
-- tests/unittest/attributes/default.md
-- tests/unittest/blank.md
-- tests/unittest/blanks_in_code.md
-- tests/unittest/bug_def.md
-- tests/unittest/bug_table.md
-- tests/unittest/code.md
-- tests/unittest/code2.md
-- tests/unittest/code3.md
-- tests/unittest/data_loss.md
-- tests/unittest/divs/div1.md
-- tests/unittest/divs/div2.md
-- tests/unittest/divs/div3_nest.md
-- tests/unittest/easy.md
-- tests/unittest/email.md
-- tests/unittest/encoding/iso-8859-1.md
-- tests/unittest/encoding/utf-8.md
-- tests/unittest/entities.md
-- tests/unittest/escaping.md
-- tests/unittest/extra_dl.md
-- tests/unittest/extra_header_id.md
-- tests/unittest/extra_table1.md
-- tests/unittest/footnotes.md
-- tests/unittest/hang.md
-- tests/unittest/headers.md
-- tests/unittest/hex_entities.md
-- tests/unittest/hrule.md
-- tests/unittest/html2.md
-- tests/unittest/html3.md
-- tests/unittest/html4.md
-- tests/unittest/html5.md
-- tests/unittest/ie.md
-- tests/unittest/images.md
-- tests/unittest/images2.md
-- tests/unittest/inline_html.md
-- tests/unittest/inline_html2.md
-- tests/unittest/links.md
-- tests/unittest/links2.md
-- tests/unittest/list1.md
-- tests/unittest/list12.md
-- tests/unittest/list2.md
-- tests/unittest/list3.md
-- tests/unittest/list4.md
-- tests/unittest/lists.md
-- tests/unittest/lists10.md
-- tests/unittest/lists11.md
-- tests/unittest/lists6.md
-- tests/unittest/lists9.md
-- tests/unittest/lists_after_paragraph.md
-- tests/unittest/lists_ol.md
-- tests/unittest/loss.md
-- tests/unittest/math/equations.md
-- tests/unittest/math/inline.md
-- tests/unittest/math/math2.md
-- tests/unittest/math/notmath.md
-- tests/unittest/math/table.md
-- tests/unittest/math/table2.md
-- tests/unittest/misc_sw.md
-- tests/unittest/notyet/escape.md
-- tests/unittest/notyet/header_after_par.md
-- tests/unittest/notyet/ticks.md
-- tests/unittest/notyet/triggering.md
-- tests/unittest/olist.md
-- tests/unittest/one.md
-- tests/unittest/paragraph.md
-- tests/unittest/paragraph_rules/dont_merge_ref.md
-- tests/unittest/paragraph_rules/tab_is_blank.md
-- tests/unittest/paragraphs.md
-- tests/unittest/pending/amps.md
-- tests/unittest/pending/empty_cells.md
-- tests/unittest/pending/link.md
-- tests/unittest/pending/ref.md
-- tests/unittest/recover/recover_links.md
-- tests/unittest/red_tests/abbrev.md
-- tests/unittest/red_tests/lists7.md
-- tests/unittest/red_tests/lists7b.md
-- tests/unittest/red_tests/lists8.md
-- tests/unittest/red_tests/xml.md
-- tests/unittest/references/long_example.md
-- tests/unittest/references/spaces_and_numbers.md
-- tests/unittest/smartypants.md
-- tests/unittest/syntax_hl.md
-- tests/unittest/table_attributes.md
-- tests/unittest/test.md
-- tests/unittest/underscore_in_words.md
-- tests/unittest/wrapping.md
-- tests/unittest/xml2.md
-- tests/unittest/xml3.md
-- tests/unittest/xml_instruction.md
-- tests/utf8-files/simple.md
-- bin/marudown
-- bin/maruku
-- bin/marutest
-- bin/marutex
-- unit_test_block.sh
-- unit_test_span.sh
-- Rakefile
-- maruku_gem.rb
-has_rdoc: false
-homepage: http://maruku.rubyforge.org
+- spec/block_docs/abbrev.md
+- spec/block_docs/abbreviations.md
+- spec/block_docs/alt.md
+- spec/block_docs/amps.md
+- spec/block_docs/attribute_sanitize.md
+- spec/block_docs/attributes/att2.md
+- spec/block_docs/attributes/att3.md
+- spec/block_docs/attributes/attributes.md
+- spec/block_docs/attributes/circular.md
+- spec/block_docs/attributes/default.md
+- spec/block_docs/auto_cdata.md
+- spec/block_docs/blank.md
+- spec/block_docs/blanks_in_code.md
+- spec/block_docs/bug_def.md
+- spec/block_docs/bug_table.md
+- spec/block_docs/code.md
+- spec/block_docs/code2.md
+- spec/block_docs/code3.md
+- spec/block_docs/code4.md
+- spec/block_docs/data_loss.md
+- spec/block_docs/div_without_newline.md
+- spec/block_docs/divs/div1.md
+- spec/block_docs/divs/div2.md
+- spec/block_docs/divs/div3_nest.md
+- spec/block_docs/easy.md
+- spec/block_docs/email.md
+- spec/block_docs/empty_cells.md
+- spec/block_docs/encoding/iso-8859-1.md
+- spec/block_docs/encoding/utf-8.md
+- spec/block_docs/entities.md
+- spec/block_docs/escape.md
+- spec/block_docs/escaping.md
+- spec/block_docs/extra_dl.md
+- spec/block_docs/extra_header_id.md
+- spec/block_docs/extra_table1.md
+- spec/block_docs/fenced_code_blocks.md
+- spec/block_docs/fenced_code_blocks_highlighted.md
+- spec/block_docs/footnotes.md
+- spec/block_docs/footnotes2.md
+- spec/block_docs/hard.md
+- spec/block_docs/header_after_par.md
+- spec/block_docs/headers.md
+- spec/block_docs/hex_entities.md
+- spec/block_docs/hrule.md
+- spec/block_docs/html3.md
+- spec/block_docs/html4.md
+- spec/block_docs/html5.md
+- spec/block_docs/html_block_in_para.md
+- spec/block_docs/html_inline.md
+- spec/block_docs/html_trailing.md
+- spec/block_docs/ie.md
+- spec/block_docs/iframe.md
+- spec/block_docs/ignore_bad_header.md
+- spec/block_docs/images.md
+- spec/block_docs/images2.md
+- spec/block_docs/inline_html.md
+- spec/block_docs/inline_html2.md
+- spec/block_docs/inline_html_beginning.md
+- spec/block_docs/issue106.md
+- spec/block_docs/issue115.md
+- spec/block_docs/issue117.md
+- spec/block_docs/issue120.md
+- spec/block_docs/issue123.md
+- spec/block_docs/issue124.md
+- spec/block_docs/issue20.md
+- spec/block_docs/issue26.md
+- spec/block_docs/issue29.md
+- spec/block_docs/issue30.md
+- spec/block_docs/issue31.md
+- spec/block_docs/issue40.md
+- spec/block_docs/issue64.md
+- spec/block_docs/issue67.md
+- spec/block_docs/issue70.md
+- spec/block_docs/issue72.md
+- spec/block_docs/issue74.md
+- spec/block_docs/issue79.md
+- spec/block_docs/issue83.md
+- spec/block_docs/issue85.md
+- spec/block_docs/issue88.md
+- spec/block_docs/issue89.md
+- spec/block_docs/issue90.md
+- spec/block_docs/link.md
+- spec/block_docs/links.md
+- spec/block_docs/links2.md
+- spec/block_docs/list1.md
+- spec/block_docs/list12.md
+- spec/block_docs/list2.md
+- spec/block_docs/list_multipara.md
+- spec/block_docs/lists.md
+- spec/block_docs/lists10.md
+- spec/block_docs/lists11.md
+- spec/block_docs/lists12.md
+- spec/block_docs/lists13.md
+- spec/block_docs/lists14.md
+- spec/block_docs/lists15.md
+- spec/block_docs/lists6.md
+- spec/block_docs/lists7b.md
+- spec/block_docs/lists9.md
+- spec/block_docs/lists_after_paragraph.md
+- spec/block_docs/lists_blank.md
+- spec/block_docs/lists_blockquote_code.md
+- spec/block_docs/lists_need_blank_line.md
+- spec/block_docs/lists_nested.md
+- spec/block_docs/lists_nested_blankline.md
+- spec/block_docs/lists_nested_deep.md
+- spec/block_docs/lists_ol.md
+- spec/block_docs/lists_paraindent.md
+- spec/block_docs/lists_tab.md
+- spec/block_docs/loss.md
+- spec/block_docs/math-blahtex/equations.md
+- spec/block_docs/math-blahtex/inline.md
+- spec/block_docs/math-blahtex/math2.md
+- spec/block_docs/math-blahtex/table.md
+- spec/block_docs/math/embedded_invalid_svg.md
+- spec/block_docs/math/embedded_svg.md
+- spec/block_docs/math/equations.md
+- spec/block_docs/math/inline.md
+- spec/block_docs/math/math2.md
+- spec/block_docs/math/notmath.md
+- spec/block_docs/math/raw_mathml.md
+- spec/block_docs/math/spaces_after_inline_math.md
+- spec/block_docs/math/table.md
+- spec/block_docs/math/table2.md
+- spec/block_docs/misc_sw.md
+- spec/block_docs/olist.md
+- spec/block_docs/one.md
+- spec/block_docs/paragraph.md
+- spec/block_docs/paragraph_rules/dont_merge_ref.md
+- spec/block_docs/paragraph_rules/tab_is_blank.md
+- spec/block_docs/paragraphs.md
+- spec/block_docs/recover/recover_links.md
+- spec/block_docs/ref_with_period.md
+- spec/block_docs/ref_with_title.md
+- spec/block_docs/references/long_example.md
+- spec/block_docs/references/spaces_and_numbers.md
+- spec/block_docs/smartypants.md
+- spec/block_docs/syntax_hl.md
+- spec/block_docs/table_attributes.md
+- spec/block_docs/table_colspan.md
+- spec/block_docs/tables.md
+- spec/block_docs/tables2.md
+- spec/block_docs/test.md
+- spec/block_docs/ticks.md
+- spec/block_docs/toc.md
+- spec/block_docs/triggering.md
+- spec/block_docs/underscore_in_words.md
+- spec/block_docs/wrapping.md
+- spec/block_docs/xml.md
+- spec/block_docs/xml3.md
+- spec/block_docs/xml_comments.md
+- spec/block_docs/xml_instruction.md
+- spec/block_spec.rb
+- spec/cli_spec.rb
+- spec/span_spec.rb
+- spec/spec_helper.rb
+- spec/to_html_utf8_spec.rb
+homepage: http://github.com/bhollis/maruku
+licenses:
+- MIT
+metadata: {}
 post_install_message: 
 rdoc_options: []
-
-require_paths: 
+require_paths:
 - lib
-required_ruby_version: !ruby/object:Gem::Requirement 
-  requirements: 
+required_ruby_version: !ruby/object:Gem::Requirement
+  requirements:
   - - ">="
-    - !ruby/object:Gem::Version 
-      version: "0"
-  version: 
-required_rubygems_version: !ruby/object:Gem::Requirement 
-  requirements: 
+    - !ruby/object:Gem::Version
+      version: 1.8.7
+required_rubygems_version: !ruby/object:Gem::Requirement
+  requirements:
   - - ">="
-    - !ruby/object:Gem::Version 
-      version: "0"
-  version: 
+    - !ruby/object:Gem::Version
+      version: '0'
 requirements: []
-
 rubyforge_project: 
-rubygems_version: 1.0.1
+rubygems_version: 2.2.0.rc.1
 signing_key: 
-specification_version: 2
+specification_version: 4
 summary: Maruku is a Markdown-superset interpreter written in Ruby.
 test_files: []
-
+has_rdoc: 
diff --git a/spec/block_docs/abbrev.md b/spec/block_docs/abbrev.md
new file mode 100644
index 0000000..4a6f1dc
--- /dev/null
+++ b/spec/block_docs/abbrev.md
@@ -0,0 +1,776 @@
+Write a comment here
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+
+WebKit (Safari 3.1) and the CSS @font-face declaration
+======================================================
+ 
+I'm a big fan of typography in general. If you check out [my homepage](http://elliottcable.name) or my [contact elliottcable](http://elliottcable.name/contact.xhtml) page, and you're using Safari/WebKit or Opera/Kestrel, you'll notice the typefaces (fonts, as colloquialized) are *very* non-standard. (As of this writing, I'm using [Museo][] and [Diavlo][][^jos] heavily on both.)
+ 
+The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We've been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and... dare I invoke ye, thou my terr [...]
+ 
+Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world.
+ 
+All hyperbole aside, I'm extremely happy to see the advent of a standard `@font-face` declaration in CSS. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary .EOT[^eot] format to appease overly restrictive type foundries' worries about intellectual property (aka. the cold, hard dominatrix that we know only as Ms. Profit) truly and completely killed that initial attempt a [...]
+ 
+Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it's an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the 'new' `@font-face` declaration. No, it's not really 'new', but yes, it feels like it is.
+ 
+To put it simply, and to be very blunt, it's broken.
+ 
+The [CSS spec section][spec] for `@font-face` is very specific - typefaces are to be selected based on a wide array of criteria placed in the `@font-face` declaration block itself. Various textual CSS attributes may be defined within the `@font-face` declaration, and then they will be checked when the typeface is referred to later in the CSS. For instance, if I have two `@font-face` declarations for the Diavlo family - one for regular text, and one for a heavier weighted version of the t [...]
+ 
+    @font-face {
+      font-family: 'Diavlo';
+      src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
+    }
+    
+    @font-face {
+      font-family: 'Diavlo';
+      font-weight: 900;
+      src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
+    }
+    
+    h1, h2, h3, h4, h5, h6 {
+      font-family: 'Diavlo';
+      font-weight: 900;
+    }
+    
+    div#content {
+      font-family: 'Diavlo';
+    }
+ 
+As you can see, my headings should use the typeface defined in `Diavlo_Black.otf`, while my body content should use `Diavlo_Book.otf`. However, in WebKit, this doesn't work - it completely ignores any attribute except `font-family:` and `src:` in a `@font-face` declaration! Completely ignores them! Not only that - not *only* that - it disregards all but the last `@font-face` for a given `font-family:` attribute string!
+ 
+The implication here is that, to make `@font-face` work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare *completely imaginary, non-existent type families* to satisfy WebKit alone. Here's the method I have used in the places I current implement `@font-face`:
+ 
+    @font-face {
+      font-family: 'Diavlo Book';
+      src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
+    }
+    
+    @font-face {
+      font-family: 'Diavlo Black';
+      src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
+    }
+    
+    h1, h2, h3, h4, h5, h6 {
+      font-family: 'Diavlo Black';
+    }
+    
+    div#content {
+      font-family: 'Diavlo Book';
+    }
+ 
+Isn't it horrible? Seriously, my eyes, they bleed. There's lots of problems with this far beyond the lack of semanticity when it comes to the typeface names... let me see how many ways this breaks the purpose of `@font-face`:
+ 
+ - You remove a large element our control over the display of the page.
+ 
+    As soon as we begin to use `@font-face` in our page, we can no longer make any use of any other textual control attribute - `font-weight:`, `font-style:`, and `font-variant:` are no longer available to us, because they no longer correctly map to technical typeface variant/features.
+    
+    Also, many default elements are destroyed, unusable, without 'fixing' - for instance, `<b>` would have no effect in a page styled for WebKit as above; We would have to specify something like `b {font-family: 'Diavlo Black';}` - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design [...]
+    
+    If we want to use Javascript to modify the display of the content, we can't simply adjust the mentioned textual control attributes - we have to know and change the entire `font-family:` array of strings.
+ 
+ - You make us very wet.
+ 
+     And by wet, I mean 'not DRY'. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typeface's bastardized name.
+ 
+ - You remove our user's user choice, and waste bandwidth.
+ 
+    Since the names refer to families that don't, in fact, exist, the browser can't override the declaration with a user's installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won't use that - it doesn't know to use 'Diavlo', which the user has installed, because it was told to use 'Diavlo Black', which no user in the entire world has installed on their computer.
+ 
+This whole thing is rather worrying - I've heard Opera has `@font-face` support, though I haven't had time to test this myself, so I don't know if it actually does - or, for that matter, if it does it 'correctly', or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support `@font-face` (Microsoft's unrelated `@font-face` declaration notwithstanding) - I really don't want to see it's early mistakes carried on to FireFox in  [...]
+ 
+In summary... come on, WebKit team, this isn't like you - you're always the ones with the closest-to-standard implementation, and the cleanest code, and... hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You're pioneering a leap into the future when it comes to the Web - this is as important, or _more_ important, than Mosiac's allowing of images was.
+ 
+To put it succinctly - don't fuck this up, y'all.
+ 
+[Museo]: <http://www.josbuivenga.demon.nl/museo.html> (Jos Buivenga's Museo free typeface)
+[Diavlo]: <http://www.josbuivenga.demon.nl/diavlo.html> (Jos Buivenga's free Diavlo typeface)
+[^jos]: These are fonts by [Jos Buivenga][jos], quite the amazing person. His (free) fonts are, uniquely, released for use on the web in `@font-face` declarations - unlike the vast majority of other (even free to download) typefaces, which have ridiculously restricting licenses and terms of use statements. Props, Jos - you're a pioneer, and deserve recognition as such.
+*[CSS]: Cascading Style Sheets
+*[.EOT]: Embedded OpenType
+[^eot]: To give Microsoft a little credit, something I rarely do... Yes, I'm aware Microsoft submitted EOT to the W3C as a proposal - the problem isn't with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry - simply decimated it. Do we really want to see the same thing happen to our beloved medium as typography moves into the 21st century?
+*[W3C]: World Wide Web Consortium
+[W3C]: <http://w3c.org> (World Wide Web Consortium)
+[spec]: <http://?> ()
+*[DRY]: Don't Repeat Yourself
+[jos]: jos
+
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:header,[
+		"WebKit (Safari 3.1) and the ",
+		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
+		" @font-face declaration"
+	],{:level=>1},[]),
+	md_par([
+		"I",
+		md_entity("rsquo"),
+		"m a big fan of typography in general. If you check out ",
+		md_im_link(["my homepage"], "http://elliottcable.name", nil),
+		" or my ",
+		md_im_link(["contact elliottcable"], "http://elliottcable.name/contact.xhtml", nil),
+		" page, and you",
+		md_entity("rsquo"),
+		"re using Safari/WebKit or Opera/Kestrel, you",
+		md_entity("rsquo"),
+		"ll notice the typefaces (fonts, as colloquialized) are ",
+		md_em(["very"]),
+		" non-standard. (As of this writing, I",
+		md_entity("rsquo"),
+		"m using ",
+		md_link(["Museo"],""),
+		" and ",
+		md_link(["Diavlo"],""),
+		md_foot_ref("^jos"),
+		" heavily on both.)"
+	]),
+	md_par([
+		"The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We",
+		md_entity("rsquo"),
+		"ve been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and",
+		md_entity("hellip"),
+		" dare I invoke ye, thou my terrible overlord? Times New Roman."
+	]),
+	md_par([
+		"Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world."
+	]),
+	md_par([
+		"All hyperbole aside, I",
+		md_entity("rsquo"),
+		"m extremely happy to see the advent of a standard ",
+		md_code("@font-face"),
+		" declaration in ",
+		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
+		". Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary ",
+		md_el(:abbr,[".EOT"],{:title=>"Embedded OpenType"},[]),
+		md_foot_ref("^eot"),
+		" format to appease overly restrictive type foundries",
+		md_entity("rsquo"),
+		" worries about intellectual property (aka. the cold, hard dominatrix that we know only as Ms. Profit) truly and completely killed that initial attempt at bringing astute typography and it",
+		md_entity("rsquo"),
+		"s advocates to the web. This new run at ",
+		md_code("@font-face"),
+		" by an established, trusted, and open group (the ",
+		md_link([md_el(:abbr,["W3C"],{:title=>"World Wide Web Consortium"},[])], ""),
+		" itself, responsible for helping to make much of what we use as designers on the web standard and cross-system compatible) has a much better chance, in my humble opinion - and I am quite looking forward to the consequences if it succeeds."
+	]),
+	md_par([
+		"Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it",
+		md_entity("rsquo"),
+		"s an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the ",
+		md_entity("lsquo"),
+		"new",
+		md_entity("rsquo"),
+		" ",
+		md_code("@font-face"),
+		" declaration. No, it",
+		md_entity("rsquo"),
+		"s not really ",
+		md_entity("lsquo"),
+		"new",
+		md_entity("rsquo"),
+		", but yes, it feels like it is."
+	]),
+	md_par([
+		"To put it simply, and to be very blunt, it",
+		md_entity("rsquo"),
+		"s broken."
+	]),
+	md_par([
+		"The ",
+		md_link([
+			md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
+			" spec section"
+		], "spec"),
+		" for ",
+		md_code("@font-face"),
+		" is very specific - typefaces are to be selected based on a wide array of criteria placed in the ",
+		md_code("@font-face"),
+		" declaration block itself. Various textual ",
+		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
+		" attributes may be defined within the ",
+		md_code("@font-face"),
+		" declaration, and then they will be checked when the typeface is referred to later in the ",
+		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
+		". For instance, if I have two ",
+		md_code("@font-face"),
+		" declarations for the Diavlo family - one for regular text, and one for a heavier weighted version of the typeface - then I later utilize Diavlo in a ",
+		md_code("font-family:"),
+		" attribute, it should refer to the basic Diavlo font defined in the first ",
+		md_code("@font-face"),
+		". However, if I were to do the same, but also specify a heavy ",
+		md_code("font-weight:"),
+		", then it should use the heavier version of Diavlo. To place this example in code:"
+	]),
+	md_el(:code,[],{:raw_code=>"@font-face {\n  font-family: 'Diavlo';\n  src: url(./Diavlo/Diavlo_Book.otf) format(\"opentype\");\n}\n\n at font-face {\n  font-family: 'Diavlo';\n  font-weight: 900;\n  src: url(./Diavlo/Diavlo_Black.otf) format(\"opentype\");\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: 'Diavlo';\n  font-weight: 900;\n}\n\ndiv#content {\n  font-family: 'Diavlo';\n}", :lang=>nil},[]),
+	md_par([
+		"As you can see, my headings should use the typeface defined in ",
+		md_code("Diavlo_Black.otf"),
+		", while my body content should use ",
+		md_code("Diavlo_Book.otf"),
+		". However, in WebKit, this doesn",
+		md_entity("rsquo"),
+		"t work - it completely ignores any attribute except ",
+		md_code("font-family:"),
+		" and ",
+		md_code("src:"),
+		" in a ",
+		md_code("@font-face"),
+		" declaration! Completely ignores them! Not only that - not ",
+		md_em(["only"]),
+		" that - it disregards all but the last ",
+		md_code("@font-face"),
+		" for a given ",
+		md_code("font-family:"),
+		" attribute string!"
+	]),
+	md_par([
+		"The implication here is that, to make ",
+		md_code("@font-face"),
+		" work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare ",
+		md_em(["completely imaginary, non-existent type families"]),
+		" to satisfy WebKit alone. Here",
+		md_entity("rsquo"),
+		"s the method I have used in the places I current implement ",
+		md_code("@font-face"),
+		":"
+	]),
+	md_el(:code,[],{:raw_code=>"@font-face {\n  font-family: 'Diavlo Book';\n  src: url(./Diavlo/Diavlo_Book.otf) format(\"opentype\");\n}\n\n at font-face {\n  font-family: 'Diavlo Black';\n  src: url(./Diavlo/Diavlo_Black.otf) format(\"opentype\");\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: 'Diavlo Black';\n}\n\ndiv#content {\n  font-family: 'Diavlo Book';\n}", :lang=>nil},[]),
+	md_par([
+		"Isn",
+		md_entity("rsquo"),
+		"t it horrible? Seriously, my eyes, they bleed. There",
+		md_entity("rsquo"),
+		"s lots of problems with this far beyond the lack of semanticity when it comes to the typeface names",
+		md_entity("hellip"),
+		" let me see how many ways this breaks the purpose of ",
+		md_code("@font-face"),
+		":"
+	]),
+	md_el(:ul,[
+		md_el(:li,[
+			md_par([
+				"You remove a large element our control over the display of the page."
+			]),
+			md_par([
+				"As soon as we begin to use ",
+				md_code("@font-face"),
+				" in our page, we can no longer make any use of any other textual control attribute - ",
+				md_code("font-weight:"),
+				", ",
+				md_code("font-style:"),
+				", and ",
+				md_code("font-variant:"),
+				" are no longer available to us, because they no longer correctly map to technical typeface variant/features."
+			]),
+			md_par([
+				"Also, many default elements are destroyed, unusable, without ",
+				md_entity("lsquo"),
+				"fixing",
+				md_entity("rsquo"),
+				" - for instance, ",
+				md_code("<b>"),
+				" would have no effect in a page styled for WebKit as above; We would have to specify something like ",
+				md_code("b {font-family: 'Diavlo Black';}"),
+				" - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design and content!), but what about comments forms? Forum posts? Direct HTML-literal quotes?"
+			]),
+			md_par([
+				"If we want to use Javascript to modify the display of the content, we can",
+				md_entity("rsquo"),
+				"t simply adjust the mentioned textual control attributes - we have to know and change the entire ",
+				md_code("font-family:"),
+				" array of strings."
+			])
+		],{:want_my_paragraph=>true},[]),
+		md_el(:li,[
+			md_par(["You make us very wet."]),
+			md_par([
+				"And by wet, I mean ",
+				md_entity("lsquo"),
+				"not ",
+				md_el(:abbr,["DRY"],{:title=>"Don't Repeat Yourself"},[]),
+				md_entity("rsquo"),
+				". What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our ",
+				md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
+				", all of our Javascript, and make sure we update every occurrence of the typeface",
+				md_entity("rsquo"),
+				"s bastardized name."
+			])
+		],{:want_my_paragraph=>true},[]),
+		md_el(:li,[
+			md_par([
+				"You remove our user",
+				md_entity("rsquo"),
+				"s user choice, and waste bandwidth."
+			]),
+			md_par([
+				"Since the names refer to families that don",
+				md_entity("rsquo"),
+				"t, in fact, exist, the browser can",
+				md_entity("rsquo"),
+				"t override the declaration with a user",
+				md_entity("rsquo"),
+				"s installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won",
+				md_entity("rsquo"),
+				"t use that - it doesn",
+				md_entity("rsquo"),
+				"t know to use ",
+				md_entity("lsquo"),
+				"Diavlo",
+				md_entity("rsquo"),
+				", which the user has installed, because it was told to use ",
+				md_entity("lsquo"),
+				"Diavlo Black",
+				md_entity("rsquo"),
+				", which no user in the entire world has installed on their computer."
+			])
+		],{:want_my_paragraph=>false},[])
+	],{},[]),
+	md_par([
+		"This whole thing is rather worrying - I",
+		md_entity("rsquo"),
+		"ve heard Opera has ",
+		md_code("@font-face"),
+		" support, though I haven",
+		md_entity("rsquo"),
+		"t had time to test this myself, so I don",
+		md_entity("rsquo"),
+		"t know if it actually does - or, for that matter, if it does it ",
+		md_entity("lsquo"),
+		"correctly",
+		md_entity("rsquo"),
+		", or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support ",
+		md_code("@font-face"),
+		" (Microsoft",
+		md_entity("rsquo"),
+		"s unrelated ",
+		md_code("@font-face"),
+		" declaration notwithstanding) - I really don",
+		md_entity("rsquo"),
+		"t want to see it",
+		md_entity("rsquo"),
+		"s early mistakes carried on to FireFox in a few years, and then Internet Explorer a few decades after that. That will leave us stuck with this broken system forever, as it has been demonstrated time and time again that if nobody else supports an old standard correctly, a newcomer to the standard will not do it correctly either. I for one would really, really, hate that."
+	]),
+	md_par([
+		"In summary",
+		md_entity("hellip"),
+		" come on, WebKit team, this isn",
+		md_entity("rsquo"),
+		"t like you - you",
+		md_entity("rsquo"),
+		"re always the ones with the closest-to-standard implementation, and the cleanest code, and",
+		md_entity("hellip"),
+		" hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You",
+		md_entity("rsquo"),
+		"re pioneering a leap into the future when it comes to the Web - this is as important, or ",
+		md_em(["more"]),
+		" important, than Mosiac",
+		md_entity("rsquo"),
+		"s allowing of images was."
+	]),
+	md_par([
+		"To put it succinctly - don",
+		md_entity("rsquo"),
+		"t fuck this up, y",
+		md_entity("rsquo"),
+		"all."
+	]),
+	md_ref_def("museo", "http://www.josbuivenga.demon.nl/museo.html", {:title=>"Jos Buivenga's Museo free typeface"}),
+	md_ref_def("diavlo", "http://www.josbuivenga.demon.nl/diavlo.html", {:title=>"Jos Buivenga's free Diavlo typeface"}),
+	md_el(:footnote,[
+	md_par([
+		"These are fonts by ",
+		md_link(["Jos Buivenga"], "jos"),
+		", quite the amazing person. His (free) fonts are, uniquely, released for use on the web in ",
+		md_code("@font-face"),
+		" declarations - unlike the vast majority of other (even free to download) typefaces, which have ridiculously restricting licenses and terms of use statements. Props, Jos - you",
+		md_entity("rsquo"),
+		"re a pioneer, and deserve recognition as such."
+	])
+	],{:footnote_id=>"^jos"},[]),
+		md_el(:abbr_def,[],{:abbr=>"CSS",:text=>"Cascading Style Sheets"},[]),
+		md_el(:abbr_def,[],{:abbr=>".EOT",:text=>"Embedded OpenType"},[]),
+		md_el(:footnote,[
+		md_par([
+		"To give Microsoft a little credit, something I rarely do",
+		md_entity("hellip"),
+		" Yes, I",
+		md_entity("rsquo"),
+		"m aware Microsoft submitted EOT to the ",
+		md_el(:abbr,["W3C"],{:title=>"World Wide Web Consortium"},[]),
+		" as a proposal - the problem isn",
+		md_entity("rsquo"),
+		"t with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry - simply decimated it. Do we really want to see the same thing happen to our beloved medium as typography moves into the 21st century?"
+	])
+	],{:footnote_id=>"^eot"},[]),
+		md_el(:abbr_def,[],{:abbr=>"W3C",:text=>"World Wide Web Consortium"},[]),
+		md_ref_def("w3c", "http://w3c.org", {:title=>"World Wide Web Consortium"}),
+		md_ref_def("spec", "http://?", {:title=>nil}),
+		md_el(:abbr_def,[],{:abbr=>"DRY",:text=>"Don't Repeat Yourself"},[]),
+		md_ref_def("jos", "jos", {:title=>nil})
+],{},[])
+*** Output of to_html ***
+<h1 id="webkit_safari_31_and_the_css_fontface_declaration">WebKit (Safari 3.1) and the <abbr title="Cascading Style Sheets">CSS</abbr> @font-face declaration</h1>
+
+<p>I’m a big fan of typography in general. If you check out <a href="http://elliottcable.name">my homepage</a> or my <a href="http://elliottcable.name/contact.xhtml">contact elliottcable</a> page, and you’re using Safari/WebKit or Opera/Kestrel, you’ll notice the typefaces (fonts, as colloquialized) are <em>very</em> non-standard. (As of this writing, I’m using <a href="http://www.josbuivenga.demon.nl/museo.html" title="Jos Buivenga's Museo free typeface">Museo</a> and <a href="http://ww [...]
+
+<p>The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We’ve been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and… dare I invoke ye, thou my ter [...]
+
+<p>Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world.</p>
+
+<p>All hyperbole aside, I’m extremely happy to see the advent of a standard <code>@font-face</code> declaration in <abbr title="Cascading Style Sheets">CSS</abbr>. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary <abbr title="Embedded OpenType">.EOT</abbr><sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup> format to appease overly restrictive type foundries’  [...]
+
+<p>Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it’s an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the ‘new’ <code>@font-face</code> declaration. No, it’s not really ‘new’, but yes, it feels like it is.</p>
+
+<p>To put it simply, and to be very blunt, it’s broken.</p>
+
+<p>The <a href="http://?"><abbr title="Cascading Style Sheets">CSS</abbr> spec section</a> for <code>@font-face</code> is very specific - typefaces are to be selected based on a wide array of criteria placed in the <code>@font-face</code> declaration block itself. Various textual <abbr title="Cascading Style Sheets">CSS</abbr> attributes may be defined within the <code>@font-face</code> declaration, and then they will be checked when the typeface is referred to later in the <abbr title=" [...]
+
+<pre><code>@font-face {
+  font-family: 'Diavlo';
+  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
+}
+
+ at font-face {
+  font-family: 'Diavlo';
+  font-weight: 900;
+  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: 'Diavlo';
+  font-weight: 900;
+}
+
+div#content {
+  font-family: 'Diavlo';
+}</code></pre>
+
+<p>As you can see, my headings should use the typeface defined in <code>Diavlo_Black.otf</code>, while my body content should use <code>Diavlo_Book.otf</code>. However, in WebKit, this doesn’t work - it completely ignores any attribute except <code>font-family:</code> and <code>src:</code> in a <code>@font-face</code> declaration! Completely ignores them! Not only that - not <em>only</em> that - it disregards all but the last <code>@font-face</code> for a given <code>font-family:</code>  [...]
+
+<p>The implication here is that, to make <code>@font-face</code> work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare <em>completely imaginary, non-existent type families</em> to satisfy WebKit alone. Here’s the method I have used in the places I current implement <code>@font-face</code>:</p>
+
+<pre><code>@font-face {
+  font-family: 'Diavlo Book';
+  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
+}
+
+ at font-face {
+  font-family: 'Diavlo Black';
+  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: 'Diavlo Black';
+}
+
+div#content {
+  font-family: 'Diavlo Book';
+}</code></pre>
+
+<p>Isn’t it horrible? Seriously, my eyes, they bleed. There’s lots of problems with this far beyond the lack of semanticity when it comes to the typeface names… let me see how many ways this breaks the purpose of <code>@font-face</code>:</p>
+
+<ul>
+<li>
+<p>You remove a large element our control over the display of the page.</p>
+
+<p>As soon as we begin to use <code>@font-face</code> in our page, we can no longer make any use of any other textual control attribute - <code>font-weight:</code>, <code>font-style:</code>, and <code>font-variant:</code> are no longer available to us, because they no longer correctly map to technical typeface variant/features.</p>
+
+<p>Also, many default elements are destroyed, unusable, without ‘fixing’ - for instance, <code><b></code> would have no effect in a page styled for WebKit as above; We would have to specify something like <code>b {font-family: 'Diavlo Black';}</code> - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document forma [...]
+
+<p>If we want to use Javascript to modify the display of the content, we can’t simply adjust the mentioned textual control attributes - we have to know and change the entire <code>font-family:</code> array of strings.</p>
+</li>
+
+<li>
+<p>You make us very wet.</p>
+
+<p>And by wet, I mean ‘not <abbr title="Don't Repeat Yourself">DRY</abbr>’. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our <abbr title="Cascading Style Sheets">CSS</abbr>, all of our Javascript, and make sure we update every occurrence of the typeface’s bastardized name.</p>
+</li>
+
+<li>
+<p>You remove our user’s user choice, and waste bandwidth.</p>
+
+<p>Since the names refer to families that don’t, in fact, exist, the browser can’t override the declaration with a user’s installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won’t use that - it doesn’t know to use ‘Diavlo’, which the user has installed, because it was told to use ‘Diavlo Black’, which no user in the entire world has installed on their computer.</p>
+</li>
+</ul>
+
+<p>This whole thing is rather worrying - I’ve heard Opera has <code>@font-face</code> support, though I haven’t had time to test this myself, so I don’t know if it actually does - or, for that matter, if it does it ‘correctly’, or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support <code>@font-face</code> (Microsoft’s unrelated <code>@font-face</code> declaration notwithstanding) - I really don’t want to see it’s earl [...]
+
+<p>In summary… come on, WebKit team, this isn’t like you - you’re always the ones with the closest-to-standard implementation, and the cleanest code, and… hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You’re pioneering a leap into the future when it comes to the Web - this is as important, or <em>more</em> important, than Mosiac’s allowing of images was.</p>
+
+<p>To put it succinctly - don’t fuck this up, y’all.</p>
+<div class="footnotes"><hr /><ol><li id="fn:1">
+<p>These are fonts by <a href="jos">Jos Buivenga</a>, quite the amazing person. His (free) fonts are, uniquely, released for use on the web in <code>@font-face</code> declarations - unlike the vast majority of other (even free to download) typefaces, which have ridiculously restricting licenses and terms of use statements. Props, Jos - you’re a pioneer, and deserve recognition as such. <a href="#fnref:1" rev="footnote">↩</a></p>
+</li><li id="fn:2">
+<p>To give Microsoft a little credit, something I rarely do… Yes, I’m aware Microsoft submitted EOT to the <abbr title="World Wide Web Consortium">W3C</abbr> as a proposal - the problem isn’t with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry - simply decimated it. Do we really want to see the same thing happen to our beloved medium as typography moves into the  [...]
+</li></ol></div>
+*** Output of to_latex ***
+\hypertarget{webkit_safari_31_and_the_css_fontface_declaration}{}\section*{{WebKit (Safari 3.1) and the CSS @font-face declaration}}\label{webkit_safari_31_and_the_css_fontface_declaration}
+
+I'm a big fan of typography in general. If you check out \href{http://elliottcable.name}{my homepage} or my \href{http://elliottcable.name/contact.xhtml}{contact elliottcable} page, and you're using Safari/WebKit or Opera/Kestrel, you'll notice the typefaces (fonts, as colloquialized) are \emph{very} non-standard. (As of this writing, I'm using \href{http://www.josbuivenga.demon.nl/museo.html}{Museo} and \href{http://www.josbuivenga.demon.nl/diavlo.html}{Diavlo}\footnote{These are fonts  [...]
+
+The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We've been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and\ldots{} dare I invoke ye, thou my [...]
+
+Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world.
+
+All hyperbole aside, I'm extremely happy to see the advent of a standard {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration in CSS. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary .EOT\footnote{To give Microsoft a little credit, something I rarely do\ldots{} Yes, I'm aware Microsoft submitted EOT to the W3C as a proposal - the problem isn't with [...]
+
+Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it's an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the `new' {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration. No, it's not really `new', but yes, it feels like it is.
+
+To put it simply, and to be very blunt, it's broken.
+
+The \href{http://?}{CSS spec section} for {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} is very specific - typefaces are to be selected based on a wide array of criteria placed in the {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration block itself. Various textual CSS attributes may be defined within the {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration, and then they will be checked when the typeface is referred to later in the [...]
+
+\begin{verbatim}@font-face {
+  font-family: 'Diavlo';
+  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
+}
+
+ at font-face {
+  font-family: 'Diavlo';
+  font-weight: 900;
+  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: 'Diavlo';
+  font-weight: 900;
+}
+
+div#content {
+  font-family: 'Diavlo';
+}\end{verbatim}
+As you can see, my headings should use the typeface defined in {\colorbox[rgb]{1.00,0.93,1.00}{\tt Diavlo\char95Black\char46otf}}, while my body content should use {\colorbox[rgb]{1.00,0.93,1.00}{\tt Diavlo\char95Book\char46otf}}. However, in WebKit, this doesn't work - it completely ignores any attribute except {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45family\char58}} and {\colorbox[rgb]{1.00,0.93,1.00}{\tt src\char58}} in a {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45fac [...]
+
+The implication here is that, to make {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare \emph{completely imaginary, non-existent type families} to satisfy WebKit alone. Here's the method I have used in the places I current implement {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}}:
+
+\begin{verbatim}@font-face {
+  font-family: 'Diavlo Book';
+  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
+}
+
+ at font-face {
+  font-family: 'Diavlo Black';
+  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: 'Diavlo Black';
+}
+
+div#content {
+  font-family: 'Diavlo Book';
+}\end{verbatim}
+Isn't it horrible? Seriously, my eyes, they bleed. There's lots of problems with this far beyond the lack of semanticity when it comes to the typeface names\ldots{} let me see how many ways this breaks the purpose of {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}}:
+
+\begin{itemize}%
+\item You remove a large element our control over the display of the page.
+
+As soon as we begin to use {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} in our page, we can no longer make any use of any other textual control attribute - {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45weight\char58}}, {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45style\char58}}, and {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45variant\char58}} are no longer available to us, because they no longer correctly map to technical typeface variant/features.
+
+Also, many default elements are destroyed, unusable, without `fixing' - for instance, {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char60b\char62}} would have no effect in a page styled for WebKit as above; We would have to specify something like {\colorbox[rgb]{1.00,0.93,1.00}{\tt b\char32\char123font\char45family\char58\char32\char39Diavlo\char32Black\char39\char59\char125}} - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead [...]
+
+If we want to use Javascript to modify the display of the content, we can't simply adjust the mentioned textual control attributes - we have to know and change the entire {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45family\char58}} array of strings.
+
+
+\item You make us very wet.
+
+And by wet, I mean `not DRY'. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typeface's bastardized name.
+
+
+\item You remove our user's user choice, and waste bandwidth.
+
+Since the names refer to families that don't, in fact, exist, the browser can't override the declaration with a user's installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won't use that - it doesn't know to use `Diavlo', which the user has installed, because it was told to use `Diavlo Black', which no user in the entire world has installed on their computer.
+
+
+
+\end{itemize}
+This whole thing is rather worrying - I've heard Opera has {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} support, though I haven't had time to test this myself, so I don't know if it actually does - or, for that matter, if it does it `correctly', or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} (Microsoft's unrelated {\colorbox[rgb]{1.00 [...]
+
+In summary\ldots{} come on, WebKit team, this isn't like you - you're always the ones with the closest-to-standard implementation, and the cleanest code, and\ldots{} hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You're pioneering a leap into the future when it comes to the Web - this is as important, or \emph{more} important, than Mosiac's allowing of images was.
+
+To put it succinctly - don't fuck this up, y'all.
+*** Output of to_md ***
+WebKit (Safari 3.1) and the CSS @font-face declarationI m a big fan of typography in general.
+If you check out my homepageor my
+contact elliottcablepage, and you re
+using Safari/WebKit or Opera/Kestrel,
+you ll notice the typefaces (fonts, as
+colloquialized) are verynon-standard.
+(As of this writing, I m using Museoand
+Diavloheavily on both.)
+
+The internet has not be a friendly
+place for typohiles like myself, up to
+this point, at least. One might even
+say it was a frightful, mentally
+scarring environment for those akin to
+yours truly. We ve been restricted to
+reading page after page after page on
+day after day after day for year after
+year after year abominations of markup
+and design enslaved by the horrible
+overlords we know as Lucida, Verdana,
+Arial, Helvetica, Geneva, Georgia,
+Courier, and dare I invoke ye, thou my
+terrible overlord? Times New Roman.
+
+Wherefore art thou, my glorious Archer?
+And thee as well, my beautiful
+Garamond? The technical restrictions of
+that horrible monster we know as the
+Web Browser hath forced us all too long
+to use those most banal, those most
+common, and those most abused, out of
+all of the typefaces of the world.
+
+All hyperbole aside, I m extremely
+happy to see the advent of a standard
+declaration in CSS. Internet Explorer
+first implemented a crutched, basic
+version of this way back in version 4,
+but nothing ever really came of it -
+their decision to create the
+proprietary .EOT format to appease
+overly restrictive type foundries
+worries about intellectual property
+(aka. the cold, hard dominatrix that we
+know only as Ms. Profit) truly and
+completely killed that initial attempt
+at bringing astute typography and it s
+advocates to the web. This new run at
+by an established, trusted, and open
+group (the W3Citself, responsible for
+helping to make much of what we use as
+designers on the web standard and
+cross-system compatible) has a much
+better chance, in my humble opinion -
+and I am quite looking forward to the
+consequences if it succeeds.
+
+Now, onwards to the topic of my post as
+declared in the header (yes, I know, a
+slow start - but it s an interesting
+topic with an interesting history!).
+WebKit, the open source rendering
+engine behind the wonderfulness that is
+Safari, and how it handles the new
+declaration. No, it s not really new ,
+but yes, it feels like it is.
+
+To put it simply, and to be very blunt,
+it s broken.
+
+The CSS spec sectionfor is very
+specific - typefaces are to be selected
+based on a wide array of criteria
+placed in the declaration block itself.
+Various textual CSS attributes may be
+defined within the declaration, and
+then they will be checked when the
+typeface is referred to later in the
+CSS. For instance, if I have two
+declarations for the Diavlo family -
+one for regular text, and one for a
+heavier weighted version of the
+typeface - then I later utilize Diavlo
+in a attribute, it should refer to the
+basic Diavlo font defined in the first
+. However, if I were to do the same,
+but also specify a heavy , then it
+should use the heavier version of
+Diavlo. To place this example in code:
+
+As you can see, my headings should use
+the typeface defined in , while my body
+content should use . However, in
+WebKit, this doesn t work - it
+completely ignores any attribute except
+and in a declaration! Completely
+ignores them! Not only that - not only
+that - it disregards all but the last
+for a given attribute string!
+
+The implication here is that, to make
+work as it is currently implemented in
+WebKit (and thus, Safari 3.1), I have
+to declare
+completely imaginary, non-existent type families
+to satisfy WebKit alone. Here s the
+method I have used in the places I
+current implement :
+
+Isn t it horrible? Seriously, my eyes,
+they bleed. There s lots of problems
+with this far beyond the lack of
+semanticity when it comes to the
+typeface names let me see how many ways
+this breaks the purpose of :
+
+-You remove a large element our control over the display of the page.
+As soon as we begin to use  in our page, we can no longer make any use of any other textual control attribute - , , and  are no longer available to us, because they no longer correctly map to technical typeface variant/features.
+Also, many default elements are destroyed, unusable, without fixing - for instance,  would have no effect in a page styled for WebKit as above; We would have to specify something like  - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design and content!), but what about comments forms [...]
+If we want to use Javascript to modify the display of the content, we cant simply adjust the mentioned textual control attributes - we have to know and change the entire  array of strings.
+-ou make us very wet.
+And by wet, I mean not DRY. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typefaces bastardized name.
+-You remove our users user choice, and waste bandwidth.
+Since the names refer to families that dont, in fact, exist, the browser cant override the declaration with a users installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser wont use that - it doesnt know to use Diavlo, which the user has installed, because it was told to use Diavlo Black, which no user in the entire world has installed on their computer.
+
+This whole thing is rather worrying - I
+ve heard Opera has support, though I
+haven t had time to test this myself,
+so I don t know if it actually does -
+or, for that matter, if it does it
+correctly , or has the same problems as
+WebKit. But either way, WebKit is one
+of the first two implementations to
+ever attempt to support (Microsoft s
+unrelated declaration notwithstanding)
+- I really don t want to see it s early
+mistakes carried on to FireFox in a few
+years, and then Internet Explorer a few
+decades after that. That will leave us
+stuck with this broken system forever,
+as it has been demonstrated time and
+time again that if nobody else supports
+an old standard correctly, a newcomer
+to the standard will not do it
+correctly either. I for one would
+really, really, hate that.
+
+In summary come on, WebKit team, this
+isn t like you - you re always the ones
+with the closest-to-standard
+implementation, and the cleanest code,
+and hell, overall? Webkit is the most
+secure/fastest browser available. But
+this is making me lose my faith in you,
+guys, please get it right. You re
+pioneering a leap into the future when
+it comes to the Web - this is as
+important, or moreimportant, than
+Mosiac s allowing of images was.
+
+To put it succinctly - don t fuck this
+up, y all.
+
+CSS: Cascading Style Sheets.EOT:
+Embedded OpenType : To give Microsoft a
+little credit, something I rarely do
+Yes, I m aware Microsoft submitted EOT
+to the W3C as a proposal - the problem
+isn t with their attempts to make it
+non-proprietary, but with the basic
+concept of making typefaces on the web
+DRMed. Look what such attempts have
+done to the music and video industry -
+simply decimated it. Do we really want
+to see the same thing happen to our
+beloved medium as typography moves into
+the 21st century?
+W3C: World Wide Web Consortium
+*** Output of to_s ***
+WebKit (Safari 3.1) and the CSS @font-face declarationIm a big fan of typography in general. If you check out my homepage or my contact elliottcable page, and youre using Safari/WebKit or Opera/Kestrel, youll notice the typefaces (fonts, as colloquialized) are very non-standard. (As of this writing, Im using Museo and Diavlo heavily on both.)The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scar [...]
diff --git a/tests/unittest/abbreviations.md b/spec/block_docs/abbreviations.md
similarity index 58%
rename from tests/unittest/abbreviations.md
rename to spec/block_docs/abbreviations.md
index 71cfc1c..cef39e2 100644
--- a/tests/unittest/abbreviations.md
+++ b/spec/block_docs/abbreviations.md
@@ -3,7 +3,7 @@ Write a comment abouth the test here.
 {}
 *** Markdown input: ***
 
-The HTML specification is maintained by the W3C.
+The HTML specification is maintained by the W3C. The W3C is headquartered in Geneva.
 
 *[HTML]: Hyper Text Markup Language
 *[W3C]:  World Wide Web Consortium
@@ -20,7 +20,9 @@ md_el(:document,[
 		md_el(:abbr,["HTML"],{:title=>"Hyper Text Markup Language"},[]),
 		" specification is maintained by the ",
 		md_el(:abbr,["W3C"],{:title=>"World Wide Web Consortium"},[]),
-		"."
+		". The ",
+		md_el(:abbr,["W3C"],{:title=>"World Wide Web Consortium"},[]),
+		" is headquartered in Geneva."
 	]),
 	md_el(:abbr_def,[],{:abbr=>"HTML",:text=>"Hyper Text Markup Language"},[]),
 	md_el(:abbr_def,[],{:abbr=>"W3C",:text=>"World Wide Web Consortium"},[]),
@@ -32,33 +34,22 @@ md_el(:document,[
 	md_el(:abbr_def,[],{:abbr=>"Tigra Genesis",:text=>nil},[])
 ],{},[])
 *** Output of to_html ***
-<p>The <abbr title='Hyper Text Markup Language'>HTML</abbr> specification is maintained by the <abbr title='World Wide Web Consortium'>W3C</abbr>.</p>
+<p>The <abbr title="Hyper Text Markup Language">HTML</abbr> specification is maintained by the <abbr title="World Wide Web Consortium">W3C</abbr>. The <abbr title="World Wide Web Consortium">W3C</abbr> is headquartered in Geneva.</p>
 
 <p>Operation <abbr>Tigra Genesis</abbr> is going well.</p>
 *** Output of to_latex ***
-The HTML specification is maintained by the W3C.
+The HTML specification is maintained by the W3C. The W3C is headquartered in Geneva.
 
 Operation Tigra Genesis is going well.
 *** Output of to_md ***
-The HTMLspecification is maintained by
-the W3C.
+The HTML specification is maintained by
+the W3C. The W3C is headquartered in
+Geneva.
 
 *[HTML]: Hyper Text Markup Language
 *[W3C]: World Wide Web Consortium
-Operation Tigra Genesisis going well.
+Operation Tigra Genesis is going well.
 
 *[Tigra Genesis]:
 *** Output of to_s ***
-The HTML specification is maintained by the W3C.Operation Tigra Genesis is going well.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+The HTML specification is maintained by the W3C. The W3C is headquartered in Geneva.Operation Tigra Genesis is going well.
diff --git a/tests/unittest/alt.md b/spec/block_docs/alt.md
similarity index 63%
rename from tests/unittest/alt.md
rename to spec/block_docs/alt.md
index 2a9e031..0314d6e 100644
--- a/tests/unittest/alt.md
+++ b/spec/block_docs/alt.md
@@ -8,22 +8,10 @@ Write a comment here
 *** Output of inspect ***
 md_el(:document,[md_par([md_im_image(["bar"], "/foo.jpg", nil)])],{},[])
 *** Output of to_html ***
-<p><img src='/foo.jpg' alt='bar' /></p>
+<p><img src="/foo.jpg" alt="bar" /></p>
 *** Output of to_latex ***
 
 *** Output of to_md ***
-bar
+![bar](/foo.jpg)
 *** Output of to_s ***
 bar
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/pending/amps.md b/spec/block_docs/amps.md
similarity index 73%
rename from tests/unittest/pending/amps.md
rename to spec/block_docs/amps.md
index 209449f..8819a7f 100644
--- a/tests/unittest/pending/amps.md
+++ b/spec/block_docs/amps.md
@@ -4,7 +4,7 @@ Write a comment here
 *** Markdown input: ***
 	@articles.map(&:title)
 *** Output of inspect ***
-md_el(:document,[md_el(:code,[],{:raw_code=>"@articles.map(&:title)"},[])],{},[])
+md_el(:document,[md_el(:code,[],{:raw_code=>"@articles.map(&:title)", :lang=>nil},[])],{},[])
 *** Output of to_html ***
 <pre><code>@articles.map(&:title)</code></pre>
 *** Output of to_latex ***
@@ -13,15 +13,3 @@ md_el(:document,[md_el(:code,[],{:raw_code=>"@articles.map(&:title)"},[])],{},[]
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/attribute_sanitize.md b/spec/block_docs/attribute_sanitize.md
new file mode 100644
index 0000000..4aa9755
--- /dev/null
+++ b/spec/block_docs/attribute_sanitize.md
@@ -0,0 +1,22 @@
+Make sure extended attributes get escaped when generating HTML: https://github.com/bhollis/maruku/issues/114
+*** Parameters: ***
+{} # params
+*** Markdown input: ***
+*foo*{: style='ball & chain'}
+
+*foo*{: style='ball\008 chain'}
+
+*foo*{: style='ball\" badAttribute=\"chain'}
+*** Output of inspect ***
+md_el(:document, [
+  md_par(md_em("foo", [["style", "ball & chain"]])),
+  md_par(md_em("foo", [["style", "ball\\008 chain"]])),
+  md_par(md_em("foo", [["style", "ball\" badAttribute=\"chain"]]))
+])
+*** Output of to_html ***
+<p><em style="ball & chain">foo</em>
+</p>
+<p><em style="ball\008 chain">foo</em>
+</p>
+<p><em style="ball" badAttribute="chain">foo</em>
+</p>
diff --git a/tests/unittest/attributes/att2.md b/spec/block_docs/attributes/att2.md
similarity index 71%
rename from tests/unittest/attributes/att2.md
rename to spec/block_docs/attributes/att2.md
index 818d40c..4018a78 100644
--- a/tests/unittest/attributes/att2.md
+++ b/spec/block_docs/attributes/att2.md
@@ -18,15 +18,3 @@ md_el(:document,[
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/attributes/att3.md b/spec/block_docs/attributes/att3.md
similarity index 70%
rename from tests/unittest/attributes/att3.md
rename to spec/block_docs/attributes/att3.md
index fe19cf9..586a757 100644
--- a/tests/unittest/attributes/att3.md
+++ b/spec/block_docs/attributes/att3.md
@@ -13,9 +13,9 @@ md_el(:document,[
 	md_par(["Paragraph2"], [[:id, "par2"]])
 ],{},[])
 *** Output of to_html ***
-<p id='par1'>Paragraph1</p>
+<p id="par1">Paragraph1</p>
 
-<p id='par2'>Paragraph2</p>
+<p id="par2">Paragraph2</p>
 *** Output of to_latex ***
 Paragraph1
 
@@ -26,15 +26,3 @@ Paragraph1
 Paragraph2
 *** Output of to_s ***
 Paragraph1Paragraph2
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/attributes/attributes.md b/spec/block_docs/attributes/attributes.md
similarity index 74%
rename from tests/unittest/attributes/attributes.md
rename to spec/block_docs/attributes/attributes.md
index 8e3d69c..6720e9e 100644
--- a/tests/unittest/attributes/attributes.md
+++ b/spec/block_docs/attributes/attributes.md
@@ -30,15 +30,15 @@ md_el(:document,[
 	md_el(:ald,[],{:ald=>[[:class, "chello"]],:ald_id=>"hello"},[])
 ],{},[])
 *** Output of to_html ***
-<h2 id='header1'>Header with attributes</h2>
+<h2 id="header1">Header with attributes</h2>
 
-<h3 id='header2'>Header with attributes</h3>
+<h3 id="header2">Header with attributes</h3>
 
-<h3 id='header_no_attributes'>Header no attributes</h3>
+<h3 id="header_no_attributes">Header no attributes</h3>
 
-<p id='par1'>Paragraph with a.</p>
+<p id="par1">Paragraph with a.</p>
 
-<p id='par2'>Paragraph with <em class='chello'>emphasis</em></p>
+<p id="par2">Paragraph with <em class="chello">emphasis</em></p>
 *** Output of to_latex ***
 \hypertarget{header1}{}\subsection*{{Header with attributes}}\label{header1}
 
@@ -50,20 +50,16 @@ Paragraph with a.
 
 Paragraph with \emph{emphasis}
 *** Output of to_md ***
-Header with attributesHeader with attributesHeader no attributesParagraph with a.
 
-Paragraph with emphasis
-*** Output of to_s ***
-Header with attributesHeader with attributesHeader no attributesParagraph with a.Paragraph with emphasis
-*** EOF ***
+## Header with attributes ##
 
+### Header with attributes ###
 
+### Header no attributes ###
 
-	OK!
-
+Paragraph with a.
 
+Paragraph with *emphasis*
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+*** Output of to_s ***
+Header with attributesHeader with attributesHeader no attributesParagraph with a.Paragraph with emphasis
diff --git a/tests/unittest/attributes/circular.md b/spec/block_docs/attributes/circular.md
similarity index 76%
rename from tests/unittest/attributes/circular.md
rename to spec/block_docs/attributes/circular.md
index 968e587..de95229 100644
--- a/tests/unittest/attributes/circular.md
+++ b/spec/block_docs/attributes/circular.md
@@ -24,15 +24,3 @@ Paragraph
 Paragraph
 *** Output of to_s ***
 Paragraph
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/attributes/default.md b/spec/block_docs/attributes/default.md
similarity index 71%
rename from tests/unittest/attributes/default.md
rename to spec/block_docs/attributes/default.md
index fa9beda..29477f3 100644
--- a/tests/unittest/attributes/default.md
+++ b/spec/block_docs/attributes/default.md
@@ -13,22 +13,10 @@ md_el(:document,[
 	md_el(:ald,[],{:ald=>[[:class, "maruku-par"]],:ald_id=>"paragraph"},[])
 ],{},[])
 *** Output of to_html ***
-<p class='maruku-par' id='2'>Paragraph2</p>
+<p id="2" class="maruku-par">Paragraph2</p>
 *** Output of to_latex ***
 Paragraph2
 *** Output of to_md ***
 Paragraph2
 *** Output of to_s ***
 Paragraph2
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/auto_cdata.md b/spec/block_docs/auto_cdata.md
new file mode 100644
index 0000000..24717d0
--- /dev/null
+++ b/spec/block_docs/auto_cdata.md
@@ -0,0 +1,48 @@
+Adds CDATA only when necessary.
+NOTE: CDATA is output because we use XHTML - for HTML mode it should be omitted.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<script>
+  var x = true && true;
+</script>
+
+<script>
+  var x = true;
+</script>
+
+<script>foo && bar</script>
+
+<script>alert('foo');</script>
+
+<style type="text/css">
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+</style>
+
+<style type="text/css">
+  .highlight {
+    color: red;
+  }
+</style>
+*** Output of inspect ***
+
+*** Output of to_html ***
+<script>//<![CDATA[
+  var x = true && true;
+//]]></script><script>
+  var x = true;
+</script><script>//<![CDATA[
+foo && bar
+//]]></script><script>alert('foo');</script><style type='text/css'>/*<![CDATA[*/
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+/*]]>*/</style><style type='text/css'>
+  .highlight {
+    color: red;
+  }
+</style>
diff --git a/tests/unittest/blank.md b/spec/block_docs/blank.md
similarity index 74%
rename from tests/unittest/blank.md
rename to spec/block_docs/blank.md
index f54fe7b..6b0433d 100644
--- a/tests/unittest/blank.md
+++ b/spec/block_docs/blank.md
@@ -22,15 +22,3 @@ Linea 1
 Linea 2
 *** Output of to_s ***
 Linea 1Linea 2
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/blanks_in_code.md b/spec/block_docs/blanks_in_code.md
similarity index 81%
rename from tests/unittest/blanks_in_code.md
rename to spec/block_docs/blanks_in_code.md
index 898e538..13240da 100644
--- a/tests/unittest/blanks_in_code.md
+++ b/spec/block_docs/blanks_in_code.md
@@ -27,11 +27,11 @@ This block is composed of 2
 *** Output of inspect ***
 md_el(:document,[
 	md_par(["This block is composed of three lines:"]),
-	md_el(:code,[],{:raw_code=>"one\n\nthree"},[]),
+	md_el(:code,[],{:raw_code=>"one\n\nthree", :lang=>nil},[]),
 	md_par(["This block is composed of 5"]),
-	md_el(:code,[],{:raw_code=>"one\n\n\nfour"},[]),
+	md_el(:code,[],{:raw_code=>"one\n\n\nfour", :lang=>nil},[]),
 	md_par(["This block is composed of 2"]),
-	md_el(:code,[],{:raw_code=>"two"},[])
+	md_el(:code,[],{:raw_code=>"two", :lang=>nil},[])
 ],{},[])
 *** Output of to_html ***
 <p>This block is composed of three lines:</p>
@@ -68,20 +68,21 @@ This block is composed of 2
 *** Output of to_md ***
 This block is composed of three lines:
 
-This block is composed of 5
-
-This block is composed of 2
-*** Output of to_s ***
-This block is composed of three lines:This block is composed of 5This block is composed of 2
-*** EOF ***
-
+     one
+     
+     three
 
+This block is composed of 5
 
-	OK!
+     one
+     
+     
+     four
 
+This block is composed of 2
 
+     two
+     
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+*** Output of to_s ***
+This block is composed of three lines:This block is composed of 5This block is composed of 2
diff --git a/tests/unittest/loss.md b/spec/block_docs/bug_def.md
similarity index 51%
copy from tests/unittest/loss.md
copy to spec/block_docs/bug_def.md
index c8c64cd..7271684 100644
--- a/tests/unittest/loss.md
+++ b/spec/block_docs/bug_def.md
@@ -2,27 +2,15 @@ Write a comment here
 *** Parameters: ***
 {} # params 
 *** Markdown input: ***
-<br/>123
+[test][]:
 
 *** Output of inspect ***
-md_el(:document,[md_html("<br />")],{},[])
+md_el(:document,[md_par([md_link(["test"], ""), ":"])],{},[])
 *** Output of to_html ***
-<br />
+<p>[test][]:</p>
 *** Output of to_latex ***
-
+test:
 *** Output of to_md ***
-
+[test][]:
 *** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+test:
diff --git a/tests/unittest/bug_table.md b/spec/block_docs/bug_table.md
similarity index 64%
rename from tests/unittest/bug_table.md
rename to spec/block_docs/bug_table.md
index 73a800c..da8fba7 100644
--- a/tests/unittest/bug_table.md
+++ b/spec/block_docs/bug_table.md
@@ -19,17 +19,17 @@ h         | h
 md_el(:document,[
 	md_par(["hello"], [["summary", "Table summary"], [:class, "class1"], ["style", "color:red"]]),
 	md_el(:table,[
-		md_el(:head_cell,["h"],{},[]),
-		md_el(:head_cell,["h"],{},[]),
-		md_el(:cell,[" c1"],{},[[:ref, "t"]]),
-		md_el(:cell,["c2"],{},[])
+		[md_el(:head_cell,["h"],{},[]),
+		md_el(:head_cell,["h"],{},[])],
+		[md_el(:cell,[" c1"],{},[[:ref, "t"]]),
+		md_el(:cell,["c2"],{},[])]
 	],{:align=>[:left, :left]},[["summary", "Table summary"], [:class, "class1"], ["style", "color:red"]]),
 	md_el(:ald,[],{:ald=>[["scope", "row"]],:ald_id=>"t"},[])
 ],{},[])
 *** Output of to_html ***
-<p class='class1' style='color:red'>hello</p>
-<table class='class1' summary='Table summary' style='color:red'><thead><tr><th>h</th><th>h</th></tr></thead><tbody><tr><th scope='row' style='text-align: left;'> c1</th><td style='text-align: left;'>c2</td>
-</tr></tbody></table>
+<p class="class1" style="color:red">hello</p>
+<table class="class1" style="color:red" summary="Table summary"><thead><tr><th>h</th><th>h</th></tr></thead><tbody><tr><th scope="row" style="text-align: left;"> c1</th><td style="text-align: left;">c2</td></tr>
+</tbody></table>
 *** Output of to_latex ***
 hello
 
@@ -44,15 +44,3 @@ hello
 hh c1c2
 *** Output of to_s ***
 hellohh c1c2
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/code.md b/spec/block_docs/code.md
similarity index 77%
rename from tests/unittest/code.md
rename to spec/block_docs/code.md
index 476bc04..8936da9 100644
--- a/tests/unittest/code.md
+++ b/spec/block_docs/code.md
@@ -12,12 +12,12 @@ Here is an example of AppleScript:
 *** Output of inspect ***
 md_el(:document,[
 	md_par(["Here is an example of AppleScript:"]),
-	md_el(:code,[],{:raw_code=>"tell application \"Foo\"\n    beep\nend tell\n\ttab"},[])
+	md_el(:code,[],{:raw_code=>"tell application \"Foo\"\n    beep\nend tell\n\ttab", :lang=>nil},[])
 ],{},[])
 *** Output of to_html ***
 <p>Here is an example of AppleScript:</p>
 
-<pre><code>tell application "Foo"
+<pre><code>tell application "Foo"
     beep
 end tell
 	tab</code></pre>
@@ -30,17 +30,10 @@ end tell
 	tab\end{verbatim}
 *** Output of to_md ***
 Here is an example of AppleScript:
+
+     tell application "Foo"
+         beep
+     end tell
+     	tab
 *** Output of to_s ***
 Here is an example of AppleScript:
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/code2.md b/spec/block_docs/code2.md
similarity index 75%
rename from tests/unittest/code2.md
rename to spec/block_docs/code2.md
index 4500db7..db38ac2 100644
--- a/tests/unittest/code2.md
+++ b/spec/block_docs/code2.md
@@ -7,7 +7,7 @@ Write a comment abouth the test here.
 >     Ciao
 *** Output of inspect ***
 md_el(:document,[
-	md_el(:quote,[md_par(["Code"]), md_el(:code,[],{:raw_code=>"Ciao"},[])],{},[])
+	md_el(:quote,[md_par(["Code"]), md_el(:code,[],{:raw_code=>"Ciao", :lang=>nil},[])],{},[])
 ],{},[])
 *** Output of to_html ***
 <blockquote>
@@ -23,18 +23,8 @@ Code
 
 \end{quote}
 *** Output of to_md ***
-Code
+> Code
+> 
+>      Ciao
 *** Output of to_s ***
 Code
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/code3.md b/spec/block_docs/code3.md
similarity index 79%
rename from tests/unittest/code3.md
rename to spec/block_docs/code3.md
index dd718f6..b35766a 100644
--- a/tests/unittest/code3.md
+++ b/spec/block_docs/code3.md
@@ -22,13 +22,13 @@ This is not code
 *** Output of inspect ***
 md_el(:document,[
 	md_par(["This is code (4 spaces):"]),
-	md_el(:code,[],{:raw_code=>"Code"},[]),
+	md_el(:code,[],{:raw_code=>"Code", :lang=>nil},[]),
 	md_par(["This is not code"]),
-	md_el(:code,[],{:raw_code=>"Code"},[]),
+	md_el(:code,[],{:raw_code=>"Code", :lang=>nil},[]),
 	md_par(["This is code (1 tab):"]),
-	md_el(:code,[],{:raw_code=>"Code"},[]),
+	md_el(:code,[],{:raw_code=>"Code", :lang=>nil},[]),
 	md_par(["This is not code"]),
-	md_el(:code,[],{:raw_code=>"Code"},[])
+	md_el(:code,[],{:raw_code=>"Code", :lang=>nil},[])
 ],{},[])
 *** Output of to_html ***
 <p>This is code (4 spaces):</p>
@@ -62,22 +62,18 @@ This is not code
 *** Output of to_md ***
 This is code (4 spaces):
 
-This is not code
-
-This is code (1 tab):
+     Code
 
 This is not code
-*** Output of to_s ***
-This is code (4 spaces):This is not codeThis is code (1 tab):This is not code
-*** EOF ***
 
+     Code
 
+This is code (1 tab):
 
-	OK!
-
+     Code
 
+This is not code
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+     Code
+*** Output of to_s ***
+This is code (4 spaces):This is not codeThis is code (1 tab):This is not code
diff --git a/spec/block_docs/code4.md b/spec/block_docs/code4.md
new file mode 100644
index 0000000..357931c
--- /dev/null
+++ b/spec/block_docs/code4.md
@@ -0,0 +1,79 @@
+Codes which look like lists
+*** Parameters: ***
+{}
+*** Markdown input: ***
+
+This is code (4 spaces):
+
+    * Code
+      * Code (again)
+
+This is also code
+
+    * Code
+	* Code (again)
+
+This is code (1 tab):
+
+	* Code
+		* Code (again)
+
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["This is code (4 spaces):"]),
+	md_el(:code,[],{:raw_code=>"* Code
+  * Code (again)", :lang=>nil},[]),
+	md_par(["This is also code"]),
+	md_el(:code,[],{:raw_code=>"* Code
+* Code (again)", :lang=>nil},[]),
+	md_par(["This is code (1 tab):"]),
+	md_el(:code,[],{:raw_code=>"* Code
+	* Code (again)", :lang=>nil},[])
+],{},[])
+*** Output of to_html ***
+<p>This is code (4 spaces):</p>
+
+<pre><code>* Code
+  * Code (again)</code></pre>
+
+<p>This is also code</p>
+
+<pre><code>* Code
+* Code (again)</code></pre>
+
+<p>This is code (1 tab):</p>
+
+<pre><code>* Code
+	* Code (again)</code></pre>
+*** Output of to_latex ***
+This is code (4 spaces):
+
+\begin{verbatim}* Code
+  * Code (again)\end{verbatim}
+This is also code
+
+\begin{verbatim}* Code
+* Code (again)\end{verbatim}
+This is code (1 tab):
+
+\begin{verbatim}* Code
+	* Code (again)\end{verbatim}
+*** Output of to_md ***
+This is code (4 spaces):
+
+     * Code
+       * Code (again)
+
+This is also code
+
+     * Code
+     * Code (again)
+
+This is code (1 tab):
+
+     * Code
+         * Code (again)
+*** Output of to_s ***
+This is code (4 spaces):This is also codeThis is code (1 tab):
+
diff --git a/tests/unittest/data_loss.md b/spec/block_docs/data_loss.md
similarity index 60%
rename from tests/unittest/data_loss.md
rename to spec/block_docs/data_loss.md
index 10a565f..a860802 100644
--- a/tests/unittest/data_loss.md
+++ b/spec/block_docs/data_loss.md
@@ -8,7 +8,7 @@ ijkl
 
 *** Output of inspect ***
 md_el(:document,[
-	md_el(:ol,[md_el(:li_span,["abcd efgh ijkl"],{:want_my_paragraph=>false},[])],{},[])
+	md_el(:ol,[md_el(:li,["abcd efgh ijkl"],{:want_my_paragraph=>false},[])],{},[])
 ],{},[])
 *** Output of to_html ***
 <ol>
@@ -20,18 +20,6 @@ md_el(:document,[
 
 \end{enumerate}
 *** Output of to_md ***
-1.  abcd efgh ijkl
+1. abcd efgh ijkl
 *** Output of to_s ***
 abcd efgh ijkl
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/div_without_newline.md b/spec/block_docs/div_without_newline.md
new file mode 100644
index 0000000..5f84a62
--- /dev/null
+++ b/spec/block_docs/div_without_newline.md
@@ -0,0 +1,16 @@
+Handle blocks of block HTML without a newline. https://github.com/bhollis/maruku/issues/123
+REXML won't clean up the HTML the way Nokogiri will...
+*** Parameters: ***
+{ }
+*** Markdown input: ***
+Heres some HTML.
+<div>
+Foo
+</div>
+*** Output of inspect ***
+
+*** Output of to_html ***
+<p>Heres some HTML.</p>
+<div>
+Foo
+</div>
diff --git a/tests/unittest/divs/div1.md b/spec/block_docs/divs/div1.md
similarity index 93%
rename from tests/unittest/divs/div1.md
rename to spec/block_docs/divs/div1.md
index 3acd7f9..0efbf62 100644
--- a/tests/unittest/divs/div1.md
+++ b/spec/block_docs/divs/div1.md
@@ -165,15 +165,3 @@ text
 text
 *** Output of to_s ***
 texttexttexttexttexttexttexttexttexttexttexttext
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/divs/div2.md b/spec/block_docs/divs/div2.md
similarity index 74%
rename from tests/unittest/divs/div2.md
rename to spec/block_docs/divs/div2.md
index 3803101..f399337 100644
--- a/tests/unittest/divs/div2.md
+++ b/spec/block_docs/divs/div2.md
@@ -19,15 +19,3 @@ ciao
 ciao
 *** Output of to_s ***
 ciao
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/divs/div3_nest.md b/spec/block_docs/divs/div3_nest.md
similarity index 85%
rename from tests/unittest/divs/div3_nest.md
rename to spec/block_docs/divs/div3_nest.md
index c4f200d..ba1815d 100644
--- a/tests/unittest/divs/div3_nest.md
+++ b/spec/block_docs/divs/div3_nest.md
@@ -1,4 +1,4 @@
-Write a comment here
+JRUBY PENDING - This is just crazy, and crashes JRuby with its crazy regexes
 *** Parameters: ***
 require 'maruku/ext/div'; {} # params 
 *** Markdown input: ***
@@ -20,12 +20,12 @@ md_el(:document,[
 	],{:label=>nil,:num=>nil,:type=>nil},[[:class, "warning"]])
 ],{},[])
 *** Output of to_html ***
-<div class='warning'>
+<div class="warning">
 <p>this is the last warning!</p>
 
 <p>please, go away!</p>
 
-<div class='menace'>
+<div class="menace">
 <p>or else terrible things will happen</p>
 </div>
 </div>
@@ -43,15 +43,3 @@ please, go away!
 or else terrible things will happen
 *** Output of to_s ***
 this is the last warning!please, go away!or else terrible things will happen
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/easy.md b/spec/block_docs/easy.md
similarity index 74%
rename from tests/unittest/easy.md
rename to spec/block_docs/easy.md
index 1d9695d..18ec30b 100644
--- a/tests/unittest/easy.md
+++ b/spec/block_docs/easy.md
@@ -10,18 +10,6 @@ md_el(:document,[md_par([md_em(["Hello!"]), " how are ", md_strong(["you"]), "?"
 *** Output of to_latex ***
 \emph{Hello!} how are \textbf{you}?
 *** Output of to_md ***
-Hello!how are you?
+*Hello!* how are **you**?
 *** Output of to_s ***
 Hello! how are you?
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/email.md b/spec/block_docs/email.md
new file mode 100644
index 0000000..d58e579
--- /dev/null
+++ b/spec/block_docs/email.md
@@ -0,0 +1,29 @@
+Write a comment abouth the test here.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+
+
+This is an email address: <andrea at invalid.it>
+	
+Address: <andrea at invalid.it>
+*** Output of inspect ***
+md_el(:document,[
+        md_par(["This is an email address: ", md_email("andrea at invalid.it")]),
+        md_par(["Address: ", md_email("andrea at invalid.it")])
+],{},[])
+*** Output of to_html ***
+<p>This is an email address: <a href="mailto:andrea at invalid.it">andrea@invalid.it</a></p>
+
+<p>Address: <a href="mailto:andrea at invalid.it">andrea@invalid.it</a></p>
+*** Output of to_latex ***
+This is an email address: \href{mailto:andrea at invalid.it}{andrea\char64invalid\char46it}
+
+Address: \href{mailto:andrea at invalid.it}{andrea\char64invalid\char46it}
+*** Output of to_md ***
+This is an email address:
+<andrea at invalid.it>
+
+Address: <andrea at invalid.it>
+*** Output of to_s ***
+This is an email address: Address:
diff --git a/spec/block_docs/empty_cells.md b/spec/block_docs/empty_cells.md
new file mode 100644
index 0000000..d13828e
--- /dev/null
+++ b/spec/block_docs/empty_cells.md
@@ -0,0 +1,31 @@
+Write a comment here
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+|    | 1  | 2  |
+|----|----|----|
+|  A | X  |    |
+|  B |    | X  |
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:table,[
+		[md_el(:head_cell,[],{},[]),md_el(:head_cell,["1"],{},[]),md_el(:head_cell,["2"],{},[])],
+		[md_el(:cell,["A"],{},[]),md_el(:cell,["X"],{},[]),md_el(:cell,[],{},[])],
+		[md_el(:cell,["B"],{},[]),md_el(:cell,[],{},[]),md_el(:cell,["X"],{},[])]
+	],{:align=>[:left, :left, :left]},[])
+],{},[])
+*** Output of to_html ***
+<table><thead><tr><th></th><th>1</th><th>2</th></tr></thead><tbody><tr><td style="text-align: left;">A</td><td style="text-align: left;">X</td><td style="text-align: left;"></td></tr>
+<tr><td style="text-align: left;">B</td><td style="text-align: left;"></td><td style="text-align: left;">X</td></tr>
+</tbody></table>
+*** Output of to_latex ***
+\begin{tabular}{l|l|l}
+&1&2\\
+\hline 
+A&X&\\
+B&&X\\
+\end{tabular}
+*** Output of to_md ***
+12AXBX
+*** Output of to_s ***
+12AXBX
diff --git a/tests/unittest/encoding/iso-8859-1.md b/spec/block_docs/encoding/iso-8859-1.md
similarity index 75%
rename from tests/unittest/encoding/iso-8859-1.md
rename to spec/block_docs/encoding/iso-8859-1.md
index 573a430..749788f 100644
--- a/tests/unittest/encoding/iso-8859-1.md
+++ b/spec/block_docs/encoding/iso-8859-1.md
@@ -17,19 +17,6 @@ md_el(:document,[
 *** Output of to_latex ***
 This is iso-8859-1: àèìàù.
 *** Output of to_md ***
-This is iso-8859-1:
-àèìàù.
+This is iso-8859-1: àèìàù.
 *** Output of to_s ***
 This is iso-8859-1: àèìàù.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/encoding/utf-8.md b/spec/block_docs/encoding/utf-8.md
similarity index 78%
rename from tests/unittest/encoding/utf-8.md
rename to spec/block_docs/encoding/utf-8.md
index b5aab08..f1c5ca8 100644
--- a/tests/unittest/encoding/utf-8.md
+++ b/spec/block_docs/encoding/utf-8.md
@@ -16,15 +16,3 @@ Japanese: マルク
 Japanese: マルク
 *** Output of to_s ***
 Japanese: マルク
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/entities.md b/spec/block_docs/entities.md
similarity index 51%
rename from tests/unittest/entities.md
rename to spec/block_docs/entities.md
index bd69b77..f8c1f59 100644
--- a/tests/unittest/entities.md
+++ b/spec/block_docs/entities.md
@@ -19,48 +19,42 @@ The following should not be translated:
 
 	©
 
-It should read just like this: `©`.
+It should read like this: `©`.
 
 
 *** Output of inspect ***
 md_el(:document,[
 	md_par(["Maruku translates HTML entities to the equivalent in LaTeX:"]),
 	md_el(:table,[
-		md_el(:head_cell,["Entity"],{},[]),
-		md_el(:head_cell,["Result"],{},[]),
-		md_el(:cell,[md_code("©")],{},[]),
-		md_el(:cell,[md_entity("copy")],{},[]),
-		md_el(:cell,[md_code("£")],{},[]),
-		md_el(:cell,[md_entity("pound")],{},[]),
-		md_el(:cell,[md_code("a b")],{},[]),
-		md_el(:cell,["a", md_entity("nbsp"), "b"],{},[]),
-		md_el(:cell,[md_code("λ")],{},[]),
-		md_el(:cell,[md_entity("lambda")],{},[]),
-		md_el(:cell,[md_code("—")],{},[]),
-		md_el(:cell,[md_entity("mdash")],{},[])
+		[md_el(:head_cell,["Entity"],{},[]),md_el(:head_cell,["Result"],{},[])],
+		[md_el(:cell,[md_code("©")],{},[]),md_el(:cell,[md_entity("copy")],{},[])],
+		[md_el(:cell,[md_code("£")],{},[]),md_el(:cell,[md_entity("pound")],{},[])],
+		[md_el(:cell,[md_code("a b")],{},[]),md_el(:cell,["a", md_entity("nbsp"), "b"],{},[])],
+		[md_el(:cell,[md_code("λ")],{},[]),md_el(:cell,[md_entity("lambda")],{},[])],
+		[md_el(:cell,[md_code("—")],{},[]),md_el(:cell,[md_entity("mdash")],{},[])]
 	],{:align=>[:left, :left]},[]),
 	md_par([
 		"Entity-substitution does not happen in code blocks or inline code."
 	]),
 	md_par(["The following should not be translated:"]),
-	md_el(:code,[],{:raw_code=>"©"},[]),
-	md_par(["It should read just like this: ", md_code("©"), "."])
+	md_el(:code,[],{:raw_code=>"©", :lang=>nil},[]),
+	md_par(["It should read like this: ", md_code("©"), "."])
 ],{},[])
 *** Output of to_html ***
 <p>Maruku translates HTML entities to the equivalent in LaTeX:</p>
-<table><thead><tr><th>Entity</th><th>Result</th></tr></thead><tbody><tr><td style='text-align: left;'><code>&copy;</code></td><td style='text-align: left;'>©</td>
-</tr><tr><td style='text-align: left;'><code>&pound;</code></td><td style='text-align: left;'>£</td>
-</tr><tr><td style='text-align: left;'><code>a&nbsp;b</code></td><td style='text-align: left;'>a b</td>
-</tr><tr><td style='text-align: left;'><code>&lambda;</code></td><td style='text-align: left;'>λ</td>
-</tr><tr><td style='text-align: left;'><code>&mdash;</code></td><td style='text-align: left;'>—</td>
-</tr></tbody></table>
+<table><thead><tr><th>Entity</th><th>Result</th></tr></thead><tbody><tr><td style="text-align: left;"><code>&copy;</code></td><td style="text-align: left;">©</td></tr>
+<tr><td style="text-align: left;"><code>&pound;</code></td><td style="text-align: left;">£</td></tr>
+<tr><td style="text-align: left;"><code>a&nbsp;b</code></td><td style="text-align: left;">a b</td></tr>
+<tr><td style="text-align: left;"><code>&lambda;</code></td><td style="text-align: left;">λ</td></tr>
+<tr><td style="text-align: left;"><code>&mdash;</code></td><td style="text-align: left;">—</td></tr>
+</tbody></table>
 <p>Entity-substitution does not happen in code blocks or inline code.</p>
 
 <p>The following should not be translated:</p>
 
 <pre><code>&copy;</code></pre>
 
-<p>It should read just like this: <code>&copy;</code>.</p>
+<p>It should read like this: <code>&copy;</code>.</p>
 *** Output of to_latex ***
 Maruku translates HTML entities to the equivalent in \LaTeX\xspace :
 
@@ -69,9 +63,9 @@ Entity&Result\\
 \hline 
 {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38copy\char59}}&\copyright{}\\
 {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38pound\char59}}&\pounds{}\\
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt a\char38nbsp\char59b}}&a~{}b\\
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38lambda\char59}}&$\lambda${}\\
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38mdash\char59}}&---{}\\
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt a\char38nbsp\char59b}}&a~b\\
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38lambda\char59}}&$\lambda$\\
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38mdash\char59}}&---\\
 \end{tabular}
 
 Entity-substitution does not happen in code blocks or inline code.
@@ -79,28 +73,26 @@ Entity-substitution does not happen in code blocks or inline code.
 The following should not be translated:
 
 \begin{verbatim}©\end{verbatim}
-It should read just like this: {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38copy\char59}}.
+It should read like this: {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char38copy\char59}}.
 *** Output of to_md ***
 Maruku translates HTML entities to the
 equivalent in LaTeX:
 
-EntityResultabEntity-substitution does not happen in
-code blocks or inline code.
-
-The following should not be translated:
-
-It should read just like this: .
-*** Output of to_s ***
-Maruku translates HTML entities to the equivalent in LaTeX:EntityResultabEntity-substitution does not happen in code blocks or inline code.The following should not be translated:It should read just like this: .
-*** EOF ***
-
+Entity      | Result
+------------|----------
+`©`    |  ©
+`£`   |  £
+`a b`  |  a b
+`λ`  |  λ
+`—`   |  —
 
 
-	OK!
+Entity-substitution does not happen in code blocks or inline code.
 
+The following should not be translated:
 
+     ©
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+It should read like this: `©`.
+*** Output of to_s ***
+Maruku translates HTML entities to the equivalent in LaTeX:EntityResultabEntity-substitution does not happen in code blocks or inline code.The following should not be translated:It should read like this: .
diff --git a/tests/unittest/notyet/escape.md b/spec/block_docs/escape.md
similarity index 60%
rename from tests/unittest/notyet/escape.md
rename to spec/block_docs/escape.md
index e2eae69..21af76f 100644
--- a/tests/unittest/notyet/escape.md
+++ b/spec/block_docs/escape.md
@@ -12,22 +12,10 @@ md_el(:document,[md_par([md_code("\\\\")]), md_par([md_code("\\")])],{},[])
 
 <p><code>\</code></p>
 *** Output of to_latex ***
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char92\char92}}
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt ~~}}
 
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char92}}
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt ~}}
 *** Output of to_md ***
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/escaping.md b/spec/block_docs/escaping.md
similarity index 70%
rename from tests/unittest/escaping.md
rename to spec/block_docs/escaping.md
index 77cb314..4841f34 100644
--- a/tests/unittest/escaping.md
+++ b/spec/block_docs/escaping.md
@@ -44,36 +44,25 @@ md_el(:document,[
 *** Output of to_latex ***
 Hello: ! ! ` \{ \} [ ] ( ) \# . ! * * *
 
-Ora, \emph{emphasis}, \textbf{bold}, * {\tt \char60}- due asterischi-{\tt \char62} * , un underscore-{\tt \char62} \_ , \emph{emphasis}, incre\emph{dible}e!
+Ora, \emph{emphasis}, \textbf{bold}, * {\tt \symbol{60}}- due asterischi-{\tt \symbol{62}} * , un underscore-{\tt \symbol{62}} \_ , \emph{emphasis}, incre\emph{dible}e!
 
-This is {\colorbox[rgb]{1.00,0.93,1.00}{\tt Code~with~a~special\char58~\char45\char62~\char96~\char60\char45}}(after)
+This is {\colorbox[rgb]{1.00,0.93,1.00}{\tt Code\char32with\char32a\char32special\char58\char32\char45\char62\char32\char96\char32\char60\char45}}(after)
 
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt Start~}} of paragraph
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt Start\char32}} of paragraph
 
-End of {\colorbox[rgb]{1.00,0.93,1.00}{\tt paragraph~}}
+End of {\colorbox[rgb]{1.00,0.93,1.00}{\tt paragraph\char32}}
 *** Output of to_md ***
-Hello: ! ! ` { } [ ] ( ) # . ! * * *
+Hello: ! \! \` \{ \} \[ \] \( \) \# \. \! * \* *
 
-Ora, emphasis, bold, * <- due
+
+Ora, *emphasis*, **bold**, * <- due
 asterischi-> * , un underscore-> _ ,
-emphasis, incre diblee!
+*emphasis*, incre*dible*e!
 
-This is (after)
+This is ``Code with a special: -> ` <- ``(after)
 
-of paragraph
+`Start ` of paragraph
 
-End of
+End of `paragraph `
 *** Output of to_s ***
 Hello: ! ! ` { } [ ] ( ) # . ! * * *Ora, emphasis, bold, * <- due asterischi-> * , un underscore-> _ , emphasis, incrediblee!This is (after) of paragraphEnd of
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/extra_dl.md b/spec/block_docs/extra_dl.md
similarity index 91%
rename from tests/unittest/extra_dl.md
rename to spec/block_docs/extra_dl.md
index 3fbab4a..c5764d6 100644
--- a/tests/unittest/extra_dl.md
+++ b/spec/block_docs/extra_dl.md
@@ -1,4 +1,5 @@
-Write a comment abouth the test here.
+Definition lists - only Maruku and Kramdown support this syntax (and only
+Kramdown gets it right.
 *** Parameters: ***
 {:css=>"style.css"}
 *** Markdown input: ***
@@ -50,15 +51,3 @@ md_el(:document,[
 ApplePomaceous fruit of plants of the genus Malus in the family Rosaceae.OrangeThe fruit of an evergreen tree of the genus Citrus.
 *** Output of to_s ***
 ApplePomaceous fruit of plants of the genus Malus in the family Rosaceae.OrangeThe fruit of an evergreen tree of the genus Citrus.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/extra_header_id.md b/spec/block_docs/extra_header_id.md
similarity index 78%
rename from tests/unittest/extra_header_id.md
rename to spec/block_docs/extra_header_id.md
index 720e4fc..97cc086 100644
--- a/tests/unittest/extra_header_id.md
+++ b/spec/block_docs/extra_header_id.md
@@ -33,15 +33,15 @@ md_el(:document,[
 	])
 ],{},[])
 *** Output of to_html ***
-<h1 id='header1'>Header 1</h1>
+<h1 id="header1">Header 1</h1>
 
-<h2 id='header2'>Header 2</h2>
+<h2 id="header2">Header 2</h2>
 
-<h3 id='header3'>Header 3</h3>
+<h3 id="header3">Header 3</h3>
 
 <p>Then you can create links to different parts of the same document like this:</p>
 
-<p><a href='#header1'>Link back to header 1</a>, <a href='#header2'>Link back to header 2</a>, <a href='#header3'>Link back to header 3</a></p>
+<p><a href="#header1">Link back to header 1</a>, <a href="#header2">Link back to header 2</a>, <a href="#header3">Link back to header 3</a></p>
 *** Output of to_latex ***
 \hypertarget{header1}{}\section*{{Header 1}}\label{header1}
 
@@ -53,23 +53,17 @@ Then you can create links to different parts of the same document like this:
 
 \hyperlink{header1}{Link back to header 1}, \hyperlink{header2}{Link back to header 2}, \hyperlink{header3}{Link back to header 3}
 *** Output of to_md ***
-Header 1Header 2Header 3Then you can create links to different
-parts of the same document like this:
-
-Link back to header 1,
-Link back to header 2,
-Link back to header 3
-*** Output of to_s ***
-Header 1Header 2Header 3Then you can create links to different parts of the same document like this:Link back to header 1, Link back to header 2, Link back to header 3
-*** EOF ***
-
-
+# Header 1 #
 
-	OK!
+## Header 2 ##
 
+### Header 3 ###
 
+Then you can create links to different
+parts of the same document like this:
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+[Link back to header 1](#header1),
+[Link back to header 2](#header2),
+[Link back to header 3](#header3)
+*** Output of to_s ***
+Header 1Header 2Header 3Then you can create links to different parts of the same document like this:Link back to header 1, Link back to header 2, Link back to header 3
diff --git a/tests/unittest/extra_table1.md b/spec/block_docs/extra_table1.md
similarity index 55%
rename from tests/unittest/extra_table1.md
rename to spec/block_docs/extra_table1.md
index 0e2ebdc..d537adb 100644
--- a/tests/unittest/extra_table1.md
+++ b/spec/block_docs/extra_table1.md
@@ -12,18 +12,18 @@ Content Cell  | Content Cell
 *** Output of inspect ***
 md_el(:document,[
 	md_el(:table,[
-		md_el(:head_cell,["First Header"],{},[]),
-		md_el(:head_cell,["Second Header"],{},[]),
-		md_el(:cell,["Content Cell"],{},[]),
-		md_el(:cell,["Content Cell"],{},[]),
-		md_el(:cell,["Content Cell"],{},[]),
-		md_el(:cell,["Content Cell"],{},[])
+		[md_el(:head_cell,["First Header"],{},[]),
+		md_el(:head_cell,["Second Header"],{},[])],
+		[md_el(:cell,["Content Cell"],{},[]),
+		md_el(:cell,["Content Cell"],{},[])],
+		[md_el(:cell,["Content Cell"],{},[]),
+		md_el(:cell,["Content Cell"],{},[])]
 	],{:align=>[:left, :left]},[])
 ],{},[])
 *** Output of to_html ***
-<table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style='text-align: left;'>Content Cell</td><td style='text-align: left;'>Content Cell</td>
-</tr><tr><td style='text-align: left;'>Content Cell</td><td style='text-align: left;'>Content Cell</td>
-</tr></tbody></table>
+<table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+</tbody></table>
 *** Output of to_latex ***
 \begin{tabular}{l|l}
 First Header&Second Header\\
@@ -35,15 +35,3 @@ Content Cell&Content Cell\\
 First HeaderSecond HeaderContent CellContent CellContent CellContent Cell
 *** Output of to_s ***
 First HeaderSecond HeaderContent CellContent CellContent CellContent Cell
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/fenced_code_blocks.md b/spec/block_docs/fenced_code_blocks.md
new file mode 100644
index 0000000..ffa97b4
--- /dev/null
+++ b/spec/block_docs/fenced_code_blocks.md
@@ -0,0 +1,58 @@
+Fenced code blocks
+*** Parameters: ***
+{ :fenced_code_blocks => true, :html_use_syntax => false }
+*** Markdown input: ***
+```ruby
+john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)
+```
+
+```
+john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)
+```
+
+~~~~~ruby
+john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)
+~~~~~~~
+
+~~~~~
+john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)
+~~~~~
+*** Output of inspect ***
+md_el(:document, [
+	md_el(:code, [], {:raw_code=>"john = Twitter::Client.new(\n  :oauth_token => \"John's access token\",\n  :oauth_token_secret => \"John's access secret\"\n)", :lang=>"ruby"}),
+	md_el(:code, [], {:raw_code=>"john = Twitter::Client.new(\n  :oauth_token => \"John's access token\",\n  :oauth_token_secret => \"John's access secret\"\n)", :lang=>nil}),
+	md_el(:code, [], {:raw_code=>"john = Twitter::Client.new(\n  :oauth_token => \"John's access token\",\n  :oauth_token_secret => \"John's access secret\"\n)", :lang=>"ruby"}),
+	md_el(:code, [], {:raw_code=>"john = Twitter::Client.new(\n  :oauth_token => \"John's access token\",\n  :oauth_token_secret => \"John's access secret\"\n)", :lang=>nil})
+])
+*** Output of to_html ***
+<pre class="ruby"><code class="ruby">john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)</code></pre>
+
+<pre><code>john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)</code></pre>
+
+<pre class="ruby"><code class="ruby">john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)</code></pre>
+
+<pre><code>john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)</code></pre>
diff --git a/spec/block_docs/fenced_code_blocks_highlighted.md b/spec/block_docs/fenced_code_blocks_highlighted.md
new file mode 100644
index 0000000..347f352
--- /dev/null
+++ b/spec/block_docs/fenced_code_blocks_highlighted.md
@@ -0,0 +1,17 @@
+Fenced code blocks
+*** Parameters: ***
+{ :fenced_code_blocks => true, :html_use_syntax => true }
+*** Markdown input: ***
+```ruby
+john = Twitter::Client.new(
+  :oauth_token => "John's access token",
+  :oauth_token_secret => "John's access secret"
+)
+```
+*** Output of inspect ***
+
+*** Output of to_html ***
+<pre class="ruby"><code class="ruby"><span class="ident">john</span> <span class="punct">=</span> <span class="constant">Twitter</span><span class="punct">::</span><span class="constant">Client</span><span class="punct">.</span><span class="ident">new</span><span class="punct">(</span>
+  <span class="symbol">:oauth_token</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">John's access token</span><span class="punct">",</span>
+  <span class="symbol">:oauth_token_secret</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">John's access secret</span><span class="punct">"</span>
+<span class="punct">)</span></code></pre>
diff --git a/tests/unittest/footnotes.md b/spec/block_docs/footnotes.md
similarity index 63%
rename from tests/unittest/footnotes.md
rename to spec/block_docs/footnotes.md
index 9ff6112..a393e7d 100644
--- a/tests/unittest/footnotes.md
+++ b/spec/block_docs/footnotes.md
@@ -54,26 +54,26 @@ md_el(:document,[
 	md_par(["This is not a footnote."])
 ],{},[])
 *** Output of to_html ***
-<p>That’s some text with a footnote <sup id='fnref:1'><a href='#fn:1' rel='footnote'>1</a></sup> and another <sup id='fnref:2'><a href='#fn:2' rel='footnote'>2</a></sup> and another <sup id='fnref:3'><a href='#fn:3' rel='footnote'>3</a></sup>.</p>
+<p>That’s some text with a footnote <sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> and another <sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup> and another <sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>.</p>
 
 <p>This is not a footnote.</p>
-<div class='footnotes'><hr /><ol><li id='fn:1'>
-<p>And that’s the footnote. This is second sentence (same paragraph).</p>
-<a href='#fnref:1' rev='footnote'>↩</a></li><li id='fn:2'>
+<div class="footnotes"><hr /><ol><li id="fn:1">
+<p>And that’s the footnote. This is second sentence (same paragraph). <a href="#fnref:1" rev="footnote">↩</a></p>
+</li><li id="fn:2">
 <p>This is the very long one.</p>
 
-<p>That’s the second paragraph.</p>
-<a href='#fnref:2' rev='footnote'>↩</a></li><li id='fn:3'>
-<p>And that’s the footnote.</p>
+<p>That’s the second paragraph. <a href="#fnref:2" rev="footnote">↩</a></p>
+</li><li id="fn:3">
+<p>And that’s the footnote.</p>
 
-<p>That’s the second paragraph of the footnote.</p>
-<a href='#fnref:3' rev='footnote'>↩</a></li></ol></div>
+<p>That’s the second paragraph of the footnote. <a href="#fnref:3" rev="footnote">↩</a></p>
+</li></ol></div>
 *** Output of to_latex ***
-That'{}s some text with a footnote \footnote{And that'{}s the footnote. This is second sentence (same paragraph).}  and another \footnote{This is the very long one.
+That's some text with a footnote \footnote{And that's the footnote. This is second sentence (same paragraph).}  and another \footnote{This is the very long one.
 
-That'{}s the second paragraph.}  and another \footnote{And that'{}s the footnote.
+That's the second paragraph.}  and another \footnote{And that's the footnote.
 
-That'{}s the second paragraph of the footnote.} .
+That's the second paragraph of the footnote.} .
 
 This is not a footnote.
 *** Output of to_md ***
@@ -95,15 +95,3 @@ That s the second paragraph.
 This is not a footnote.
 *** Output of to_s ***
 Thats some text with a footnote  and another  and another .And thats the footnote.Thats the second paragraph of the footnote.And thats the footnote. This is second sentence (same paragraph).This is the very long one.Thats the second paragraph.This is not a footnote.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/footnotes2.md b/spec/block_docs/footnotes2.md
new file mode 100644
index 0000000..1d8c9ec
--- /dev/null
+++ b/spec/block_docs/footnotes2.md
@@ -0,0 +1,81 @@
+Write a comment abouth the test here.
+*** Parameters: ***
+require 'maruku/ext/math';{:html_math_engine => 'itex2mml'}
+*** Markdown input: ***
+Ruby on Rails is a web-framework[^framework]. It uses the MVC[^MVC] architecture pattern. It has its good points[^points].
+
+[^framework]: a reusable set of libraries
+[^MVC]: Model View Controller
+[^points]: Here are its good points
+     1. Ease of use
+     2. Rapid development
+
+That has nothing to do with putting equations in footnotes[^equations].
+
+[^equations]: Like this:
+$$
+  x = r\cos\theta
+$$
+*** Output of inspect ***
+md_el(:document,[
+	md_par([
+		"Ruby on Rails is a web-framework",
+		md_foot_ref("^framework"),
+		". It uses the MVC",
+		md_foot_ref("^MVC"),
+		" architecture pattern. It has its good points",
+		md_foot_ref("^points"),
+		"."
+	]),
+	md_el(:footnote, md_par("a reusable set of libraries"), {:footnote_id=>"^framework"}),
+	md_el(:footnote, md_par("Model View Controller"), {:footnote_id=>"^MVC"}),
+	md_el(:footnote, [
+		md_par("Here are its good points"),
+		md_el(:ol, [md_li("Ease of use", false), md_li("Rapid development", false)])
+		], {:footnote_id=>"^points"}),
+	md_par([
+		"That has nothing to do with putting equations in footnotes",
+		md_foot_ref("^equations"),
+		"."
+		]),
+	md_el(:footnote, [
+		md_par("Like this:"),
+		md_el(:equation, [], {:math=>"\nx = r\\cos\\theta\n\n", :label=>nil, :num=>nil})
+		], {:footnote_id=>"^equations"})
+],{},[])
+*** Output of to_html ***
+<p>Ruby on Rails is a web-framework<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>. It uses the MVC<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup> architecture pattern. It has its good points<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>.</p>
+
+<p>That has nothing to do with putting equations in footnotes<sup id="fnref:4"><a href="#fn:4" rel="footnote">4</a></sup>.</p>
+<div class="footnotes"><hr /><ol><li id="fn:1">
+<p>a reusable set of libraries <a href="#fnref:1" rev="footnote">↩</a></p>
+</li><li id="fn:2">
+<p>Model View Controller <a href="#fnref:2" rev="footnote">↩</a></p>
+</li><li id="fn:3">
+<p>Here are its good points</p>
+
+<ol>
+<li>Ease of use</li>
+
+<li>Rapid development</li>
+</ol>
+<a href="#fnref:3" rev="footnote">↩</a></li><li id="fn:4">
+<p>Like this:</p>
+<div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>x</mi><mo>=</mo><mi>r</mi><mi>cos</mi><mi>θ</mi></mrow><annotation encoding="application/x-tex">
+x = r\cos\theta
+
+</annotation></semantics></math></div><a href="#fnref:4" rev="footnote">↩</a></li></ol></div>
+*** Output of to_latex ***
+Ruby on Rails is a web-framework\footnote{a reusable set of libraries} . It uses the MVC\footnote{Model View Controller}  architecture pattern. It has its good points\footnote{Here are its good points
+
+\begin{enumerate}%
+\item Ease of use
+\item Rapid development
+
+\end{enumerate}} .
+
+That has nothing to do with putting equations in footnotes\footnote{Like this:
+
+\begin{displaymath}
+x = r\cos\theta
+\end{displaymath}} .
\ No newline at end of file
diff --git a/spec/block_docs/hard.md b/spec/block_docs/hard.md
new file mode 100644
index 0000000..45c14ac
--- /dev/null
+++ b/spec/block_docs/hard.md
@@ -0,0 +1,25 @@
+More complicated tests for emphasis.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+*This is in italic, and **this is bold italics**.*  But **is this bold and *this bold-italic* **? Or just plain ***bold italics***.
+*** Output of inspect ***
+md_el(:document,
+  [md_par([
+    md_em([
+      "This is in italic, and ", md_strong(["this is bold italics"]), "."
+    ]), " But ", md_strong([
+                   "is this bold and ", md_em(["this bold-italic"])
+                 ]), "? Or just plain ", md_emstrong(["bold italics"]), "."
+   ])
+  ],{},[])
+*** Output of to_html ***
+<p><em>This is in italic, and <strong>this is bold italics</strong>.</em> But <strong>is this bold and <em>this bold-italic</em></strong>? Or just plain <strong><em>bold italics</em></strong>.</p>
+*** Output of to_latex ***
+\emph{This is in italic, and \textbf{this is bold italics}.} But \textbf{is this bold and \emph{this bold-italic}}? Or just plain \textbf{\emph{bold italics}}.
+*** Output of to_md ***
+*This is in italic, and **this is bold italics**.*
+But **is this bold and *this bold-italic* **? Or
+just plain ***bold italics***.
+*** Output of to_s ***
+This is in italic, and this is bold italics. But is this bold and this bold-italic? Or just plain bold italics.
diff --git a/spec/block_docs/header_after_par.md b/spec/block_docs/header_after_par.md
new file mode 100644
index 0000000..9060c33
--- /dev/null
+++ b/spec/block_docs/header_after_par.md
@@ -0,0 +1,62 @@
+Write a comment abouth the test here.
+*** Parameters: ***
+{:title=>"header"}
+*** Markdown input: ***
+Paragraph
+### header 1 ###
+
+Paragraph
+header 2
+--------
+
+Paragraph
+header 3
+========
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["Paragraph"]),
+	md_el(:header,["header 1"],{:level=>3},[]),
+	md_par(["Paragraph"]),
+	md_el(:header,["header 2"],{:level=>2},[]),
+	md_par(["Paragraph"]),
+	md_el(:header,["header 3"],{:level=>1},[])
+],{},[])
+*** Output of to_html ***
+<p>Paragraph</p>
+
+<h3 id="header_1">header 1</h3>
+
+<p>Paragraph</p>
+
+<h2 id="header_2">header 2</h2>
+
+<p>Paragraph</p>
+
+<h1 id="header_3">header 3</h1>
+*** Output of to_latex ***
+Paragraph
+
+\hypertarget{header_1}{}\subsubsection*{{header 1}}\label{header_1}
+
+Paragraph
+
+\hypertarget{header_2}{}\subsection*{{header 2}}\label{header_2}
+
+Paragraph
+
+\hypertarget{header_3}{}\section*{{header 3}}\label{header_3}
+*** Output of to_md ***
+Paragraph
+
+### header
+
+Paragraph
+
+## header
+
+Paragraph
+
+# header
+*** Output of to_s ***
+ParagraphheaderParagraphheaderParagraphheader
diff --git a/tests/unittest/headers.md b/spec/block_docs/headers.md
similarity index 56%
rename from tests/unittest/headers.md
rename to spec/block_docs/headers.md
index 981739e..355c8e8 100644
--- a/tests/unittest/headers.md
+++ b/spec/block_docs/headers.md
@@ -20,30 +20,22 @@ md_el(:document,[
 	md_el(:header,["A title with ", md_em(["emphasis"])],{:level=>4},[])
 ],{},[])
 *** Output of to_html ***
-<h1 id='a_title_with_emphasis'>A title with <em>emphasis</em></h1>
+<h1 id="a_title_with_emphasis">A title with <em>emphasis</em></h1>
 
-<h2 id='a_title_with_emphasis'>A title with <em>emphasis</em></h2>
+<h2 id="a_title_with_emphasis_2">A title with <em>emphasis</em></h2>
 
-<h4 id='a_title_with_emphasis'>A title with <em>emphasis</em></h4>
+<h4 id="a_title_with_emphasis_3">A title with <em>emphasis</em></h4>
 *** Output of to_latex ***
 \hypertarget{a_title_with_emphasis}{}\section*{{A title with \emph{emphasis}}}\label{a_title_with_emphasis}
 
-\hypertarget{a_title_with_emphasis}{}\subsection*{{A title with \emph{emphasis}}}\label{a_title_with_emphasis}
+\hypertarget{a_title_with_emphasis_2}{}\subsection*{{A title with \emph{emphasis}}}\label{a_title_with_emphasis_2}
 
-\hypertarget{a_title_with_emphasis}{}\paragraph*{{A title with \emph{emphasis}}}\label{a_title_with_emphasis}
+\hypertarget{a_title_with_emphasis_3}{}\paragraph*{{A title with \emph{emphasis}}}\label{a_title_with_emphasis_3}
 *** Output of to_md ***
-A title with emphasisA title with emphasisA title with emphasis
-*** Output of to_s ***
-A title with emphasisA title with emphasisA title with emphasis
-*** EOF ***
-
-
+# A title with *emphasis* #
 
-	OK!
+## A title with *emphasis* ##
 
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+#### A title with *emphasis* ####
+*** Output of to_s ***
+A title with emphasisA title with emphasisA title with emphasis
diff --git a/tests/unittest/hex_entities.md b/spec/block_docs/hex_entities.md
similarity index 63%
rename from tests/unittest/hex_entities.md
rename to spec/block_docs/hex_entities.md
index 04d72ab..6d1435f 100644
--- a/tests/unittest/hex_entities.md
+++ b/spec/block_docs/hex_entities.md
@@ -24,26 +24,15 @@ md_el(:document,[
 	])
 ],{},[])
 *** Output of to_html ***
-<p>Examples of numeric character references include © or © for the copyright symbol, Α or Α for the Greek capital letter alpha, and ا or ا for the Arabic letter alef.</p>
+<p>Examples of numeric character references include © or © for the copyright symbol, Α or Α for the Greek capital letter alpha, and ا or ا for the Arabic letter alef.</p>
 *** Output of to_latex ***
-Examples of numeric character references include \copyright{} or \copyright{} for the copyright symbol, $A${} or $A${} for the Greek capital letter alpha, and  or  for the Arabic letter alef.
+Examples of numeric character references include \copyright{} or \copyright{} for the copyright symbol, $A$ or $A$ for the Greek capital letter alpha, and  or  for the Arabic letter alef.
 *** Output of to_md ***
 Examples of numeric character
-references include or for the copyright
-symbol, or for the Greek capital letter
-alpha, and or for the Arabic letter
-alef.
+references include &169; or &169; for
+the copyright symbol, &913; or &913;
+for the Greek capital letter alpha,
+and &1575; or &1575; for the Arabic
+letter alef.
 *** Output of to_s ***
 Examples of numeric character references include  or  for the copyright symbol,  or  for the Greek capital letter alpha, and  or  for the Arabic letter alef.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/hrule.md b/spec/block_docs/hrule.md
similarity index 83%
rename from tests/unittest/hrule.md
rename to spec/block_docs/hrule.md
index 9a63748..5321c50 100644
--- a/tests/unittest/hrule.md
+++ b/spec/block_docs/hrule.md
@@ -35,17 +35,10 @@ md_el(:document,[
 \vspace{.5em} \hrule \vspace{.5em}
 *** Output of to_md ***
 
+* * *
+* * *
+* * *
+* * *
+* * *
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/html3.md b/spec/block_docs/html3.md
similarity index 71%
rename from tests/unittest/html3.md
rename to spec/block_docs/html3.md
index 6bf2439..8549bf3 100644
--- a/tests/unittest/html3.md
+++ b/spec/block_docs/html3.md
@@ -22,22 +22,10 @@ md_el(:document,[
 	])
 ],{},[])
 *** Output of to_html ***
-<p>taking part in <a href='http://sied.dis.uniroma1.it/'>some arcane conspirations</a> which involve <b href='http://www.flickr.com/photos/censi/70893277/'>coffee</b>, <a href='http://flickr.com/photos/censi/42775664/in/set-936677/'>robots</a>, <a href='http://www.flickr.com/photos/censi/42775888/in/set-936677/'>sushi</a>,</p>
+<p>taking part in <a href="http://sied.dis.uniroma1.it/">some arcane conspirations</a> which involve <b href="http://www.flickr.com/photos/censi/70893277/">coffee</b>, <a href="http://flickr.com/photos/censi/42775664/in/set-936677/">robots</a>, <a href="http://www.flickr.com/photos/censi/42775888/in/set-936677/">sushi</a>,</p>
 *** Output of to_latex ***
 taking part in  which involve , , ,
 *** Output of to_md ***
 taking part in which involve , , ,
 *** Output of to_s ***
 taking part in  which involve , , ,
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/html4.md b/spec/block_docs/html4.md
similarity index 67%
rename from tests/unittest/html4.md
rename to spec/block_docs/html4.md
index 7a4e87f..0632991 100644
--- a/tests/unittest/html4.md
+++ b/spec/block_docs/html4.md
@@ -14,8 +14,8 @@ md_el(:document,[
 	md_html("<div class=\"frame\">\n\t<a  class=\"photo\" href=\"http://www.flickr.com/photos/censi/54757256/\"><img alt=\"\"\n  moz-do-not-send=\"true\"\n  src=\"http://static.flickr.com/27/54757256_1a2c1d2a95_m.jpg\" /></a>\n</div>")
 ],{},[])
 *** Output of to_html ***
-<div class='frame'>
-	<a href='http://www.flickr.com/photos/censi/54757256/' class='photo'><img src='http://static.flickr.com/27/54757256_1a2c1d2a95_m.jpg' moz-do-not-send='true' alt='' /></a>
+<div class="frame">
+	<a class="photo" href="http://www.flickr.com/photos/censi/54757256/"><img alt="" moz-do-not-send="true" src="http://static.flickr.com/27/54757256_1a2c1d2a95_m.jpg" /></a>
 </div>
 *** Output of to_latex ***
 
@@ -23,15 +23,3 @@ md_el(:document,[
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/html5.md b/spec/block_docs/html5.md
similarity index 67%
rename from tests/unittest/html5.md
rename to spec/block_docs/html5.md
index 82a0c60..7baa4b3 100644
--- a/tests/unittest/html5.md
+++ b/spec/block_docs/html5.md
@@ -12,8 +12,8 @@ md_el(:document,[
 	md_html(" <div class=\"frame\">\n <a class=\"photo\" href=\"http://www.flickr.com/photos/censi/88561568/\" ><img moz-do-not-send=\"true\" src=\"http://static.flickr.com/28/88561568_ab84d28245_m.jpg\" width=\"240\" height=\"180\" alt=\"Aperitif\" /></a>\n </div>")
 ],{},[])
 *** Output of to_html ***
-<div class='frame'>
- <a href='http://www.flickr.com/photos/censi/88561568/' class='photo'><img src='http://static.flickr.com/28/88561568_ab84d28245_m.jpg' height='180' moz-do-not-send='true' alt='Aperitif' width='240' /></a>
+<div class="frame">
+ <a class="photo" href="http://www.flickr.com/photos/censi/88561568/"><img moz-do-not-send="true" src="http://static.flickr.com/28/88561568_ab84d28245_m.jpg" width="240" height="180" alt="Aperitif" /></a>
  </div>
 *** Output of to_latex ***
 
@@ -21,15 +21,3 @@ md_el(:document,[
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/html_block_in_para.md b/spec/block_docs/html_block_in_para.md
new file mode 100644
index 0000000..d772f0d
--- /dev/null
+++ b/spec/block_docs/html_block_in_para.md
@@ -0,0 +1,22 @@
+Maruku should not nest block-level HTML inside a paragraph
+*** Parameters: ***
+{} # params
+*** Markdown input: ***
+One
+<div>a</div>123
+
+<div>a</div>123
+*** Output of inspect ***
+md_el(:document,[
+	md_par("One"),
+  md_html("<div>a</div>"),
+  md_par("123"),
+	md_html("<div>a</div>"),
+  md_par("123")
+],{},[])
+*** Output of to_html ***
+<p>One</p>
+<div>a</div>
+<p>123</p>
+<div>a</div>
+<p>123</p>
diff --git a/spec/block_docs/html_inline.md b/spec/block_docs/html_inline.md
new file mode 100644
index 0000000..42a98eb
--- /dev/null
+++ b/spec/block_docs/html_inline.md
@@ -0,0 +1,25 @@
+JRUBY NOKOGIRI PENDING - Maruku should nest inline-level HTML inside a paragraph
+(JRuby Nokogiri is broken for empty tags: https://github.com/sparklemotion/nokogiri/issues/971)
+*** Parameters: ***
+{} # params
+*** Markdown input: ***
+One
+<span></span>123
+
+<span></span>123
+
+<animateColor/>123
+
+<svg></svg>
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["One ", md_html("<span></span>"), "123"]),
+	md_par([md_html("<span></span>"), "123"]),
+	md_par([md_html("<animateColor/>"), "123"]),
+	md_html("<svg></svg>"),
+],{},[])
+*** Output of to_html ***
+<p>One <span></span>123</p>
+<p><span></span>123</p>
+<p><animateColor></animateColor>123</p>
+<svg></svg>
diff --git a/spec/block_docs/html_trailing.md b/spec/block_docs/html_trailing.md
new file mode 100644
index 0000000..4e8c2f5
--- /dev/null
+++ b/spec/block_docs/html_trailing.md
@@ -0,0 +1,31 @@
+Markdown should be processed trailing text after HTML
+*** Parameters: ***
+{}
+*** Markdown input: ***
+before
+
+<!-- comment --> ------
+
+after
+
+<p>hello</p> *foo*
+
+done
+*** Output of inspect ***
+md_el(:document, [
+       md_par("before"),
+       md_html("<!-- comment -->"),
+       md_el(:hrule, []),
+       md_par("after"),
+       md_html("<p>hello</p>"),
+       md_par(md_em("foo")),
+       md_par("done") ])
+*** Output of to_html ***
+<p>before</p>
+<!-- comment --><hr />
+
+<p>after</p>
+<p>hello</p>
+<p><em>foo</em></p>
+
+<p>done</p>
\ No newline at end of file
diff --git a/spec/block_docs/ie.md b/spec/block_docs/ie.md
new file mode 100644
index 0000000..3e2fe39
--- /dev/null
+++ b/spec/block_docs/ie.md
@@ -0,0 +1,62 @@
+We must make sure that `'` is always written as `'`.
+
+*** Parameters: ***
+{:html_use_syntax => true} # params 
+*** Markdown input: ***
+`<p>here's an apostrophe & a quote "</p>`
+
+	<p>here's an apostrophe & a quote "</p>
+{:}
+
+	<p>here's an apostrophe & a quote "</p>
+{:lang=xml}
+
+	<p>here's an apostrophe & a quote "</p>
+{:html_use_syntax=true lang=not_supported}
+
+	<p>here's an apostrophe & a quote "</p>
+{:html_use_syntax=true lang=xml}
+
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par([md_code("<p>here's an apostrophe & a quote \"</p>")]),
+	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>", :lang=>nil},[]),
+	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>", :lang=>nil},[["lang", "xml"]]),
+	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>", :lang=>nil},[["html_use_syntax", "true"], ["lang", "not_supported"]]),
+	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>", :lang=>nil},[["html_use_syntax", "true"], ["lang", "xml"]])
+],{},[])
+*** Output of to_html ***
+<p><code><p>here's an apostrophe & a quote "</p></code></p>
+
+<pre><code><p>here's an apostrophe & a quote "</p></code></pre>
+
+<pre class="xml"><code class="xml"><span class="punct"><</span><span class="tag">p</span><span class="punct">></span>here's an apostrophe & a quote "<span class="punct"></</span><span class="tag">p</span><span class="punct">></span></code></pre>
+
+<pre class="not_supported"><code class="not_supported"><p>here's an apostrophe & a quote "</p></code></pre>
+
+<pre class="xml"><code class="xml"><span class="punct"><</span><span class="tag">p</span><span class="punct">></span>here's an apostrophe & a quote "<span class="punct"></</span><span class="tag">p</span><span class="punct">></span></code></pre>
+*** Output of to_latex ***
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char60p\char62here\char39s\char32an\char32apostrophe\char32\char38\char32a\char32quote\char32\char34\char60\char47p\char62}}
+
+\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
+\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
+\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
+\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
+*** Output of to_md ***
+
+`<p>here's an apostrophe & a quote "</p>`
+
+     <p>here's an apostrophe & a quote "</p>
+{:}
+
+     <p>here's an apostrophe & a quote "</p>
+{:lang=xml}
+
+     <p>here's an apostrophe & a quote "</p>
+{:html_use_syntax=true lang=not_supported}
+
+     <p>here's an apostrophe & a quote "</p>
+{:html_use_syntax=true lang=xml}
+*** Output of to_s ***
+
diff --git a/tests/unittest/paragraph_rules/tab_is_blank.md b/spec/block_docs/iframe.md
similarity index 53%
copy from tests/unittest/paragraph_rules/tab_is_blank.md
copy to spec/block_docs/iframe.md
index 1527380..ac50768 100644
--- a/tests/unittest/paragraph_rules/tab_is_blank.md
+++ b/spec/block_docs/iframe.md
@@ -1,16 +1,21 @@
-Paragraphs eat blank lines.
-The following are two paragraphs:
+Embed html iframe element
 *** Parameters: ***
 {}
 *** Markdown input: ***
 Paragraph1
-	
+
+<iframe src="http://www.youtube.com/">a</iframe>
+
 Paragraph2
 *** Output of inspect ***
-md_el(:document,[md_par(["Paragraph1"]), md_par(["Paragraph2"])],{},[])
+md_el(:document,[
+	md_par(["Paragraph1"]),
+	md_html('<iframe src="http://www.youtube.com/">a</iframe>'),
+	md_par(["Paragraph2"])
+],{},[])
 *** Output of to_html ***
 <p>Paragraph1</p>
-
+<iframe src="http://www.youtube.com/">a</iframe>
 <p>Paragraph2</p>
 *** Output of to_latex ***
 Paragraph1
@@ -22,15 +27,3 @@ Paragraph1
 Paragraph2
 *** Output of to_s ***
 Paragraph1Paragraph2
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/ignore_bad_header.md b/spec/block_docs/ignore_bad_header.md
new file mode 100644
index 0000000..1bce751
--- /dev/null
+++ b/spec/block_docs/ignore_bad_header.md
@@ -0,0 +1,9 @@
+Pass weird messed up header through to output without blowing up. Secondary issue noticed via https://github.com/bhollis/maruku/issues/124
+*** Parameters: ***
+{:on_error => :raise}
+*** Markdown input: ***
+= Markdown, with some ruby =
+*** Output of inspect ***
+md_el(:document, md_par(["= Markdown, with some ruby ="]))
+*** Output of to_html ***
+<p>= Markdown, with some ruby =</p>
diff --git a/tests/unittest/images.md b/spec/block_docs/images.md
similarity index 57%
rename from tests/unittest/images.md
rename to spec/block_docs/images.md
index ea03607..034d045 100644
--- a/tests/unittest/images.md
+++ b/spec/block_docs/images.md
@@ -3,7 +3,7 @@ Write a comment abouth the test here.
 {}
 *** Markdown input: ***
 
-This page does not uilizes ![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss)
+This page does not utilize ![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss)
 
 
 Please mouseover to see the title: ![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss "Title ok!")
@@ -27,7 +27,7 @@ This is double size: ![Cascading Style Sheets] [css2]
 *** Output of inspect ***
 md_el(:document,[
 	md_par([
-		"This page does not uilizes ",
+		"This page does not utilize ",
 		md_im_image(["Cascading Style Sheets"], "http://jigsaw.w3.org/css-validator/images/vcss", nil)
 	]),
 	md_par([
@@ -52,51 +52,45 @@ md_el(:document,[
 	md_ref_def("css2", "http://jigsaw.w3.org/css-validator/images/vcss", {:title=>"Optional title attribute"})
 ],{},[])
 *** Output of to_html ***
-<p>This page does not uilizes <img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Cascading Style Sheets' /></p>
+<p>This page does not utilize <img src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Cascading Style Sheets" /></p>
 
-<p>Please mouseover to see the title: <img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Cascading Style Sheets' /></p>
+<p>Please mouseover to see the title: <img src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Cascading Style Sheets" title="Title ok!" /></p>
 
-<p>Please mouseover to see the title: <img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Cascading Style Sheets' /></p>
+<p>Please mouseover to see the title: <img src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Cascading Style Sheets" title="Title ok!" /></p>
 
-<p>I’ll say it one more time: this page does not use <img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Cascading Style Sheets' /></p>
+<p>I’ll say it one more time: this page does not use <img src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Cascading Style Sheets" title="Optional title attribute" /></p>
 
-<p>This is double size: <img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Cascading Style Sheets' /></p>
+<p>This is double size: <img src="http://jigsaw.w3.org/css-validator/images/vcss" alt="Cascading Style Sheets" title="Optional title attribute" /></p>
 *** Output of to_latex ***
-This page does not uilizes 
+This page does not utilize 
 
 Please mouseover to see the title: 
 
 Please mouseover to see the title: 
 
-I'{}ll say it one more time: this page does not use 
+I'll say it one more time: this page does not use 
 
 This is double size:
 *** Output of to_md ***
-This page does not uilizes
-Cascading Style Sheets
+This page does not utilize
+![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss)
 
 Please mouseover to see the title:
-Cascading Style Sheets
+![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss "Title ok!")
 
 Please mouseover to see the title:
-Cascading Style Sheets
+![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss "Title ok!")
 
-I ll say it one more time: this page
-does not use Cascading Style Sheets
+I'll say it one more time: this
+page does not use
+![Cascading Style Sheets][css]
 
 This is double size:
-Cascading Style Sheets
-*** Output of to_s ***
-This page does not uilizes Cascading Style SheetsPlease mouseover to see the title: Cascading Style SheetsPlease mouseover to see the title: Cascading Style SheetsIll say it one more time: this page does not use Cascading Style SheetsThis is double size: Cascading Style Sheets
-*** EOF ***
-
-
-
-	OK!
-
+![Cascading Style Sheets][css2]
 
+[css]: http://jigsaw.w3.org/css-validator/images/vcss "Optional title attribute"
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+[css2]: http://jigsaw.w3.org/css-validator/images/vcss "Optional title attribute" class=external
+   style="border:0;width:188px;height:131px"
+*** Output of to_s ***
+This page does not utilize Cascading Style SheetsPlease mouseover to see the title: Cascading Style SheetsPlease mouseover to see the title: Cascading Style SheetsIll say it one more time: this page does not use Cascading Style SheetsThis is double size: Cascading Style Sheets
diff --git a/tests/unittest/images2.md b/spec/block_docs/images2.md
similarity index 58%
rename from tests/unittest/images2.md
rename to spec/block_docs/images2.md
index d541268..60b576f 100644
--- a/tests/unittest/images2.md
+++ b/spec/block_docs/images2.md
@@ -11,33 +11,23 @@ This is an ![image].
 
 *** Output of inspect ***
 md_el(:document,[
-	md_par(["This is an ", md_image(["image"], "image"), "."]),
+	md_par(["This is an ", md_image(["image"], ""), "."]),
 	md_par(["This is an ", md_image(["image"], "image"), "."]),
 	md_ref_def("image", "image.jpg", {:title=>nil})
 ],{},[])
 *** Output of to_html ***
-<p>This is an <img src='image.jpg' alt='image' />.</p>
+<p>This is an <img src="image.jpg" alt="image" />.</p>
 
-<p>This is an <img src='image.jpg' alt='image' />.</p>
+<p>This is an <img src="image.jpg" alt="image" />.</p>
 *** Output of to_latex ***
 This is an .
 
 This is an .
 *** Output of to_md ***
-This is an image.
+This is an ![image][].
+
+This is an ![image].
 
-This is an image.
+[image]: image.jpg
 *** Output of to_s ***
 This is an image.This is an image.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/inline_html.md b/spec/block_docs/inline_html.md
similarity index 53%
rename from tests/unittest/inline_html.md
rename to spec/block_docs/inline_html.md
index 9652a92..4e2c9ef 100644
--- a/tests/unittest/inline_html.md
+++ b/spec/block_docs/inline_html.md
@@ -6,13 +6,13 @@ CSS: style.css
 
 Input:
 
-	<em>Emphasis</em>
+    <em>Emphasis</em>
 
 Result: <em>Emphasis</em>
 
 Input:
 
-	<img src="http://jigsaw.w3.org/css-validator/images/vcss"/>
+    <img src="http://jigsaw.w3.org/css-validator/images/vcss"/>
 
 Result on span: <img src="http://jigsaw.w3.org/css-validator/images/vcss"/>
 
@@ -25,14 +25,14 @@ Without closing:
 <img src="http://jigsaw.w3.org/css-validator/images/vcss">
 
 <div markdown="1">
-	This is *true* markdown text (paragraph)
-
-	<p markdown="1">
-		This is *true* markdown text (no paragraph)
-	</p>
-	<p markdown="block">
-		This is *true* markdown text (block paragraph)
-	</p>
+   This is *true* markdown text (paragraph)
+
+   <p markdown="1">
+   This is *true* markdown text (no paragraph)
+   </p>
+   <p markdown="block">
+   This is *true* markdown text (block paragraph)
+   </p>
 </div>
 
 <table>
@@ -47,19 +47,19 @@ Without closing:
 *** Output of inspect ***
 md_el(:document,[
 	md_par(["Input:"]),
-	md_el(:code,[],{:raw_code=>"<em>Emphasis</em>"},[]),
+	md_el(:code,[],{:raw_code=>"<em>Emphasis</em>", :lang=>nil},[]),
 	md_par(["Result: ", md_html("<em>Emphasis</em>")]),
 	md_par(["Input:"]),
-	md_el(:code,[],{:raw_code=>"<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\"/>"},[]),
+	md_el(:code,[],{:raw_code=>"<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\"/>", :lang=>nil},[]),
 	md_par([
 		"Result on span: ",
 		md_html("<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\" />")
 	]),
 	md_par(["Result alone:"]),
-	md_html("<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\" />"),
+	md_par(md_html("<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\" />")),
 	md_par(["Without closing:"]),
-	md_html("<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\" />"),
-	md_html("<div markdown=\"1\">\n\tThis is *true* markdown text (paragraph)\n\n\t<p markdown=\"1\">\n\t\tThis is *true* markdown text (no paragraph)\n\t</p>\n\t<p markdown=\"block\">\n\t\tThis is *true* markdown text (block paragraph)\n\t</p>\n</div>"),
+	md_par(md_html("<img src=\"http://jigsaw.w3.org/css-validator/images/vcss\" />")),
+	md_html("<div markdown=\"1\">\n   This is *true* markdown text (paragraph)\n\n   <p markdown=\"1\">\n   This is *true* markdown text (no paragraph)\n   </p>\n   <p markdown=\"block\">\n   This is *true* markdown text (block paragraph)\n   </p>\n</div>"),
 	md_html("<table>\n<tr>\n<td markdown=\"1\">This is a *true* markdown text. (no par)</td>\n<td markdown=\"block\">This is *true* markdown text. (par)</td>\n</tr>\n</table>")
 ],{},[])
 *** Output of to_html ***
@@ -71,57 +71,37 @@ md_el(:document,[
 
 <p>Input:</p>
 
-<pre><code><img src="http://jigsaw.w3.org/css-validator/images/vcss"/></code></pre>
+<pre><code><img src="http://jigsaw.w3.org/css-validator/images/vcss"/></code></pre>
 
-<p>Result on span: <img src='http://jigsaw.w3.org/css-validator/images/vcss' /></p>
+<p>Result on span: <img src="http://jigsaw.w3.org/css-validator/images/vcss" /></p>
 
 <p>Result alone:</p>
-<img src='http://jigsaw.w3.org/css-validator/images/vcss' />
+
+<p><img src="http://jigsaw.w3.org/css-validator/images/vcss" /></p>
+
 <p>Without closing:</p>
-<img src='http://jigsaw.w3.org/css-validator/images/vcss' /><div>
-<p>
-<p>This is</p>
-<em>
-<p>true</p>
-</em>
-<p>markdown text (paragraph)</p>
-</p>
-<p>
-<p>
-<p>This is</p>
-<em>
-<p>true</p>
-</em>
-<p>markdown text (no paragraph)</p>
-</p>
-</p>
-	<p>
-<p>
-<p>This is</p>
-<em>
-<p>true</p>
-</em>
-<p>markdown text (block paragraph)</p>
-</p>
+
+<p><img src="http://jigsaw.w3.org/css-validator/images/vcss" /></p>
+<div>
+<p>This is <em>true</em> markdown text (paragraph)</p>
+
+
+   <p>
+   This is <em>true</em> markdown text (no paragraph)
+   </p>
+   <p>
+<p>This is <em>true</em> markdown text (block paragraph)</p>
+
 </p>
 </div><table>
 <tr>
+<td>This is a <em>true</em> markdown text. (no par)</td>
 <td>
-<p>This is a</p>
-<em>
-<p>true</p>
-</em>
-<p>markdown text. (no par)</p>
-</td>
-<td>
-<p>This is</p>
-<em>
-<p>true</p>
-</em>
-<p>markdown text. (par)</p>
+<p>This is <em>true</em> markdown text. (par)</p>
 </td>
 </tr>
 </table>
+
 *** Output of to_latex ***
 Input:
 
@@ -135,6 +115,8 @@ Result on span:
 
 Result alone:
 
+
+
 Without closing:
 *** Output of to_md ***
 Input:
@@ -150,15 +132,3 @@ Result alone:
 Without closing:
 *** Output of to_s ***
 Input:Result: Input:Result on span: Result alone:Without closing:
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/inline_html2.md b/spec/block_docs/inline_html2.md
similarity index 77%
rename from tests/unittest/inline_html2.md
rename to spec/block_docs/inline_html2.md
index 7d070a4..609f139 100644
--- a/tests/unittest/inline_html2.md
+++ b/spec/block_docs/inline_html2.md
@@ -1,4 +1,4 @@
-
+Markdown inside HTML according to Markdown Extra: http://michelf.ca/projects/php-markdown/extra/#markdown-attr
 *** Parameters: ***
 {}
 *** Markdown input: ***
@@ -19,15 +19,3 @@ md_el(:document,[
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/inline_html_beginning.md b/spec/block_docs/inline_html_beginning.md
new file mode 100644
index 0000000..cc95de2
--- /dev/null
+++ b/spec/block_docs/inline_html_beginning.md
@@ -0,0 +1,10 @@
+Inline HTML at the beginning of a line shouldn't kill the rest of the line. https://github.com/bhollis/maruku/issues/67
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<del>Two</del> Half
+*** Output of inspect ***
+md_el(:document, md_par([md_html("<del>Two</del>"), " Half"]))
+*** Output of to_html ***
+<p><del>Two</del> Half</p>
+
diff --git a/spec/block_docs/issue106.md b/spec/block_docs/issue106.md
new file mode 100644
index 0000000..c34a50b
--- /dev/null
+++ b/spec/block_docs/issue106.md
@@ -0,0 +1,78 @@
+Code with list-delimiters in it - https://github.com/bhollis/maruku/issues/106
+*** Parameters: ***
+{}
+*** Markdown input: ***
+
+This is code (4 spaces):
+
+    * Code
+      * Code (again)
+
+This is also code
+
+    * Code
+	* Code (again)
+
+This is code (1 tab):
+
+	* Code
+		* Code (again)
+
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["This is code (4 spaces):"]),
+	md_el(:code,[],{:raw_code=>"* Code
+  * Code (again)", :lang=>nil},[]),
+	md_par(["This is also code"]),
+	md_el(:code,[],{:raw_code=>"* Code
+* Code (again)", :lang=>nil},[]),
+	md_par(["This is code (1 tab):"]),
+	md_el(:code,[],{:raw_code=>"* Code
+	* Code (again)", :lang=>nil},[])
+],{},[])
+*** Output of to_html ***
+<p>This is code (4 spaces):</p>
+
+<pre><code>* Code
+  * Code (again)</code></pre>
+
+<p>This is also code</p>
+
+<pre><code>* Code
+* Code (again)</code></pre>
+
+<p>This is code (1 tab):</p>
+
+<pre><code>* Code
+	* Code (again)</code></pre>
+*** Output of to_latex ***
+This is code (4 spaces):
+
+\begin{verbatim}* Code
+  * Code (again)\end{verbatim}
+This is also code
+
+\begin{verbatim}* Code
+* Code (again)\end{verbatim}
+This is code (1 tab):
+
+\begin{verbatim}* Code
+	* Code (again)\end{verbatim}
+*** Output of to_md ***
+This is code (4 spaces):
+
+     * Code
+       * Code (again)
+
+This is also code
+
+     * Code
+     * Code (again)
+
+This is code (1 tab):
+
+     * Code
+         * Code (again)
+*** Output of to_s ***
+This is code (4 spaces):This is also codeThis is code (1 tab):
diff --git a/spec/block_docs/issue115.md b/spec/block_docs/issue115.md
new file mode 100644
index 0000000..07bd656
--- /dev/null
+++ b/spec/block_docs/issue115.md
@@ -0,0 +1,20 @@
+Markdown in comments should not be parsed. https://github.com/bhollis/maruku/issues/115
+Note that output is kind of weird because we modify the comment in order to let REXML parse it due to https://bugs.ruby-lang.org/issues/9277.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<!--
+Header
+------
+-->
+
+<!-- -- -->
+*** Output of inspect ***
+md_el(:document,[md_html("<!--\nHeader\n- - - - - - \n-->"), md_html("<!-- - - -->")])
+*** Output of to_html ***
+<!--
+Header
+- - - - - - 
+-->
+
+<!-- - - -->
diff --git a/spec/block_docs/issue117.md b/spec/block_docs/issue117.md
new file mode 100644
index 0000000..bd01c91
--- /dev/null
+++ b/spec/block_docs/issue117.md
@@ -0,0 +1,13 @@
+Section tags should not get <p> put around them. https://github.com/bhollis/maruku/issues/117
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<section markdown="1">
+## Header
+</section>
+*** Output of inspect ***
+
+*** Output of to_html ***
+<section>
+<h2>Header</h2>
+</section>
diff --git a/spec/block_docs/issue120.md b/spec/block_docs/issue120.md
new file mode 100644
index 0000000..8c9113c
--- /dev/null
+++ b/spec/block_docs/issue120.md
@@ -0,0 +1,48 @@
+Style tags should be OK with unescaped angle brackets and ampersands. https://github.com/bhollis/maruku/issues/120
+NOTE: Commented CDATA is output because we use XHTML - for HTML mode it should be omitted.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<style type="text/css">
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+</style>
+
+<style type="text/css">/*<![CDATA[*/
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+/*]]>*/</style>
+
+<style type="text/css">
+/*<![CDATA[*/
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+/*]]>*/
+</style>
+*** Output of inspect ***
+
+*** Output of to_html ***
+<style type='text/css'>/*<![CDATA[*/
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+/*]]>*/</style><style type='text/css'>/*<![CDATA[*/
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+/*]]>*/</style><style type='text/css'>
+/*<![CDATA[*/
+  p > .highlight {
+    color: red;
+    background-image: url('/foo?bar&baz');
+  }
+/*]]>*/
+</style>
diff --git a/spec/block_docs/issue123.md b/spec/block_docs/issue123.md
new file mode 100644
index 0000000..f2db594
--- /dev/null
+++ b/spec/block_docs/issue123.md
@@ -0,0 +1,11 @@
+Handle script tag without a newline. https://github.com/bhollis/maruku/issues/123
+*** Parameters: ***
+{ }
+*** Markdown input: ***
+Lets add Jade to our dependencies:
+<script src="https://gist.github.com/7360992.js"> </script>
+*** Output of inspect ***
+
+*** Output of to_html ***
+<p>Lets add Jade to our dependencies:</p>
+<script src='https://gist.github.com/7360992.js'> </script>
diff --git a/spec/block_docs/issue124.md b/spec/block_docs/issue124.md
new file mode 100644
index 0000000..aefbdbe
--- /dev/null
+++ b/spec/block_docs/issue124.md
@@ -0,0 +1,16 @@
+Handle blocks of inline HTML without a newline without complaining. https://github.com/bhollis/maruku/issues/124
+*** Parameters: ***
+{:on_error => :raise}
+*** Markdown input: ***
+What follows uses ruby
+<ruby>
+    <rb>東</rb><rp>(</rp><rt>トウ</rt><rp>)</rp>
+    <rb>京</rb><rp>(</rp><rt>キョウ</rt><rp>)</rp>
+</ruby>.
+*** Output of inspect ***
+
+*** Output of to_html ***
+<p>What follows uses ruby <ruby>
+    <rb>東</rb><rp>(</rp><rt>トウ</rt><rp>)</rp>
+    <rb>京</rb><rp>(</rp><rt>キョウ</rt><rp>)</rp>
+</ruby>.</p>
diff --git a/spec/block_docs/issue20.md b/spec/block_docs/issue20.md
new file mode 100644
index 0000000..d1007bd
--- /dev/null
+++ b/spec/block_docs/issue20.md
@@ -0,0 +1,9 @@
+Just an attribute list on its own in a header is probably really content. https://github.com/bhollis/maruku/issues/20
+*** Parameters: ***
+{}
+*** Markdown input: ***
+# {hi}
+*** Output of inspect ***
+md_el(:document, md_el(:header, "{hi}", {:level=>1}))
+*** Output of to_html ***
+<h1 id="hi">{hi}</h1>
diff --git a/spec/block_docs/issue26.md b/spec/block_docs/issue26.md
new file mode 100644
index 0000000..f33abfe
--- /dev/null
+++ b/spec/block_docs/issue26.md
@@ -0,0 +1,22 @@
+Nested lists shouldn't get <p> tags wrapped around elements. https://github.com/bhollis/maruku/issues/26
+*** Parameters: ***
+{}
+*** Markdown input: ***
+ -  Root
+     +  Node
+     +  Node
+ -  Root
+*** Output of inspect ***
+md_el(:document, md_el(:ul, [
+	md_li(["Root", md_el(:ul, [md_li("Node", false), md_li("Node", false)])], false),
+	md_li("Root", false)
+]))
+*** Output of to_html ***
+<ul>
+<li>Root
+<ul>
+<li>Node</li>
+<li>Node</li>
+</ul></li>
+<li>Root</li>
+</ul>
diff --git a/spec/block_docs/issue29.md b/spec/block_docs/issue29.md
new file mode 100644
index 0000000..4544f6e
--- /dev/null
+++ b/spec/block_docs/issue29.md
@@ -0,0 +1,9 @@
+Generating ids for unicode headers. Other markdown implementations drop the non-ASCII characters so the anchor is URL-valid. https://github.com/bhollis/maruku/issues/29
+*** Parameters: ***
+{}
+*** Markdown input: ***
+# Übersicht
+*** Output of inspect ***
+md_el(:document, md_el(:header, "Übersicht", {:level=>1}))
+*** Output of to_html ***
+<h1 id='bersicht'>Übersicht</h1>
diff --git a/spec/block_docs/issue30.md b/spec/block_docs/issue30.md
new file mode 100644
index 0000000..8ddc7f5
--- /dev/null
+++ b/spec/block_docs/issue30.md
@@ -0,0 +1,30 @@
+List markers typically start at the left margin, but may be indented by up to three spaces. https://github.com/bhollis/maruku/issues/30
+*** Parameters: ***
+{}
+*** Markdown input: ***
+This is a list:
+
+  * a list
+
+And this:
+
+   * still a list
+*** Output of inspect ***
+md_el(:document, [
+	md_par("This is a list:"),
+	md_el(:ul, md_el(:li, "a list", {:want_my_paragraph=>false})),
+	md_par("And this:"),
+	md_el(:ul, md_el(:li, "still a list", {:want_my_paragraph=>false}))
+])
+*** Output of to_html ***
+<p>This is a list:</p>
+
+<ul>
+<li>a list</li>
+</ul>
+
+<p>And this:</p>
+
+<ul>
+<li>still a list</li>
+</ul>
diff --git a/spec/block_docs/issue31.md b/spec/block_docs/issue31.md
new file mode 100644
index 0000000..9d8fbe7
--- /dev/null
+++ b/spec/block_docs/issue31.md
@@ -0,0 +1,25 @@
+Markdown should be processed inside span-level tags. https://github.com/bhollis/maruku/issues/31
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<span>*hello*</span>
+
+<p><span>*hello*</span></p>
+
+<span>hello <span>*there*</span></span>
+
+<span>hello
+<span>*there*</span></span>
+*** Output of inspect ***
+md_el(:document, [
+  md_par(md_html("<span>*hello*</span>")),
+  md_html("<p><span>*hello*</span></p>"),
+  md_par(md_html("<span>hello <span>*there*</span></span>")),
+  md_par(md_html("<span>hello\n<span>*there*</span></span>"))
+])
+*** Output of to_html ***
+<p><span><em>hello</em></span></p>
+<p><span>*hello*</span></p>
+<p><span>hello <span><em>there</em></span></span></p>
+<p><span>hello
+<span><em>there</em></span></span></p>
\ No newline at end of file
diff --git a/spec/block_docs/issue40.md b/spec/block_docs/issue40.md
new file mode 100644
index 0000000..e05d7e5
--- /dev/null
+++ b/spec/block_docs/issue40.md
@@ -0,0 +1,52 @@
+Script tags should be OK with unescaped ampersands. https://github.com/bhollis/maruku/issues/40
+NOTE: CDATA is output because we use XHTML - for HTML mode it should be omitted.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<script>
+  var x = true && true;
+</script>
+
+<script>foo && bar</script>
+
+<script><![CDATA[
+  var x = true && true;
+]]></script>
+
+<script><![CDATA[foo && bar]]></script>
+
+<script>
+<![CDATA[
+  var x = true && true;
+]]>
+</script>
+
+<script>//<![CDATA[
+  var x = true && true;
+//]]></script>
+
+<script>
+//<![CDATA[
+  var x = true && true;
+//]]>
+</script>
+*** Output of inspect ***
+
+*** Output of to_html ***
+<script>//<![CDATA[
+  var x = true && true;
+//]]></script><script>//<![CDATA[
+foo && bar
+//]]></script><script><![CDATA[
+  var x = true && true;
+]]></script><script><![CDATA[foo && bar]]></script><script>
+<![CDATA[
+  var x = true && true;
+]]>
+</script><script>//<![CDATA[
+  var x = true && true;
+//]]></script><script>
+//<![CDATA[
+  var x = true && true;
+//]]>
+</script>
diff --git a/spec/block_docs/issue64.md b/spec/block_docs/issue64.md
new file mode 100644
index 0000000..6c1c640
--- /dev/null
+++ b/spec/block_docs/issue64.md
@@ -0,0 +1,55 @@
+Nested list with a single item. https://github.com/bhollis/maruku/issues/64
+*** Parameters: ***
+{}
+*** Markdown input: ***
+A nested list with a single item (does not work)
+
+- three items:
+  - item 1
+  - item 2
+  - item 3
+- one item:
+  - item
+- two items:
+  - item a
+  - item b
+
+*** Output of inspect ***
+md_el(:document, [
+	md_par("A nested list with a single item (does not work)"),
+	md_el(:ul, [
+	md_li([
+	"three items:",
+	md_el(:ul, [
+	md_li("item 1", false),
+	md_li("item 2", false),
+	md_li("item 3", false)
+])
+], false),
+	md_li(["one item:", md_el(:ul, md_li("item", false))], false),
+	md_li([
+	"two items:",
+	md_el(:ul, [md_li("item a", false), md_li("item b", false)])
+], false)
+])
+])
+*** Output of to_html ***
+<p>A nested list with a single item (does not work)</p>
+
+<ul>
+<li>three items:
+<ul>
+<li>item 1</li>
+<li>item 2</li>
+<li>item 3</li>
+</ul></li>
+<li>one item:
+<ul>
+<li>item</li>
+</ul></li>
+<li>two items:
+<ul>
+<li>item a</li>
+<li>item b</li>
+</ul></li>
+</ul>
diff --git a/spec/block_docs/issue67.md b/spec/block_docs/issue67.md
new file mode 100644
index 0000000..dbaa604
--- /dev/null
+++ b/spec/block_docs/issue67.md
@@ -0,0 +1,19 @@
+A span at the beginning of a list item shouldn't cause the other list elements to be wrapped in paragraphs or remove the inline element. https://github.com/bhollis/maruku/issues/67
+*** Parameters: ***
+{}
+*** Markdown input: ***
+- One
+- <del>Two</del>
+- Three
+*** Output of inspect ***
+md_el(:document, md_el(:ul, [
+	md_li("One", false),
+	md_li(md_html("<del>Two</del>"), false),
+	md_li("Three", false)
+]))
+*** Output of to_html ***
+<ul>
+  <li>One</li>
+  <li><del>Two</del></li>
+  <li>Three</li>
+</ul>
diff --git a/spec/block_docs/issue70.md b/spec/block_docs/issue70.md
new file mode 100644
index 0000000..778f6f3
--- /dev/null
+++ b/spec/block_docs/issue70.md
@@ -0,0 +1,11 @@
+Lines should be able to start with @. Note that a leading space doesn't
+trigger the old metadata syntax. https://github.com/bhollis/maruku/issues/70
+*** Parameters: ***
+{}
+*** Markdown input: ***
+@ foo
+*** Output of inspect ***
+md_el(:document, md_par("@ foo"))
+*** Output of to_html ***
+<p>@ foo</p>
+
diff --git a/spec/block_docs/issue72.md b/spec/block_docs/issue72.md
new file mode 100644
index 0000000..aa5c64c
--- /dev/null
+++ b/spec/block_docs/issue72.md
@@ -0,0 +1,17 @@
+https://github.com/bhollis/maruku/issues/72
+*** Parameters: ***
+{}
+*** Markdown input: ***
+1. 句子 
+2. 句子
+*** Output of inspect ***
+md_el(:document, md_el(:ol, [
+	md_el(:li, "句子", {:want_my_paragraph=>false}),
+	md_el(:li, "句子", {:want_my_paragraph=>false})
+]))
+*** Output of to_html ***
+<ol>
+<li>句子</li>
+
+<li>句子</li>
+</ol>
diff --git a/spec/block_docs/issue74.md b/spec/block_docs/issue74.md
new file mode 100644
index 0000000..d74a468
--- /dev/null
+++ b/spec/block_docs/issue74.md
@@ -0,0 +1,38 @@
+https://github.com/bhollis/maruku/issues/74
+*** Parameters: ***
+{}
+*** Markdown input: ***
+## Cool Title
+
+<ul>
+    <li>Cool Text yada yada</li>
+    <li>ICool Tex 2 yada yada</li>
+</ul>
+
+
+
+<p id="icons">
+    <a href="" class="stumbleupon" target="_blank">a</a>
+    <a href="" class="stumbleupon" target="_blank">a</a>
+    <a href="" class="stumbleupon" target="_blank">a</a>
+</p>
+
+## Recents Post
+*** Output of inspect ***
+md_el(:document, [
+     	md_el(:header, "Cool Title", {:level=>2}),
+     	md_html("<ul>\n    <li>Cool Text yada yada</li>\n    <li>ICool Tex 2 yada yada</li>\n</ul>"),
+     	md_html("<p id=\"icons\">\n    <a href=\"\" class=\"stumbleupon\" target=\"_blank\">a</a>\n    <a href=\"\" class=\"stumbleupon\" target=\"_blank\">a</a>\n    <a href=\"\" class=\"stumbleupon\" target=\"_blank\">a</a>\n</p>"),
+     	md_el(:header, "Recents Post", {:level=>2})
+     ])
+*** Output of to_html ***
+<h2 id="cool_title">Cool Title</h2>
+<ul>
+    <li>Cool Text yada yada</li>
+    <li>ICool Tex 2 yada yada</li>
+</ul><p id="icons">
+    <a href="" class="stumbleupon" target="_blank">a</a>
+    <a href="" class="stumbleupon" target="_blank">a</a>
+    <a href="" class="stumbleupon" target="_blank">a</a>
+</p>
+<h2 id="recents_post">Recents Post</h2>
diff --git a/spec/block_docs/issue79.md b/spec/block_docs/issue79.md
new file mode 100644
index 0000000..70e91ad
--- /dev/null
+++ b/spec/block_docs/issue79.md
@@ -0,0 +1,15 @@
+Non-ASCII characters in a PRE tag. See https://github.com/bhollis/maruku/issues/79
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<p>á é í ó ú</p>
+
+<pre>
+á é í ó ú
+</pre>
+*** Output of inspect ***
+md_el(:document, [md_html("<p>á é í ó ú</p>"), md_html("<pre>\ná é í ó ú\n</pre>")])
+*** Output of to_html ***
+<p>á é í ó ú</p><pre>
+á é í ó ú
+</pre>
diff --git a/spec/block_docs/issue83.md b/spec/block_docs/issue83.md
new file mode 100644
index 0000000..b9141fc
--- /dev/null
+++ b/spec/block_docs/issue83.md
@@ -0,0 +1,13 @@
+Maruku confused by HTML that contains @ signs. See https://github.com/bhollis/maruku/issues/83
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<div><span>@Foo</span>
+
+</div>
+*** Output of inspect ***
+md_el(:document, md_html("<div><span>@Foo</span>\n\n</div>"))
+*** Output of to_html ***
+<div><span>@Foo</span>
+
+</div>
\ No newline at end of file
diff --git a/spec/block_docs/issue85.md b/spec/block_docs/issue85.md
new file mode 100644
index 0000000..ca30e0b
--- /dev/null
+++ b/spec/block_docs/issue85.md
@@ -0,0 +1,25 @@
+Escaped content in raw HTML. See https://github.com/bhollis/maruku/issues/85
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<pre><span class="cp">#include <foo> &#x201c;</span></pre>
+
+Foo <span><code>#include <foo> &#x201c;</code></span> bar
+
+Foo <span class="cp">#include <foo> &#x201c;</span> bar
+*** Output of inspect ***
+md_el(:document, [md_html("<pre><span class=\"cp\">#include <foo> &#x201c;</span></pre>"),
+        md_par([
+        "Foo ",
+        md_html("<span><code>#include <foo> &#x201c;</code></span>"),
+        " bar"]),
+        md_par([
+        "Foo ",
+        md_html("<span class=\"cp\">#include <foo> &#x201c;</span>"),
+        " bar"])
+])
+*** Output of to_html ***
+<pre><span class="cp">#include <foo> “</span></pre>
+<p>Foo <span><code>#include <foo> “</code></span> bar</p>
+
+<p>Foo <span class="cp">#include <foo> “</span> bar</p>
\ No newline at end of file
diff --git a/spec/block_docs/issue88.md b/spec/block_docs/issue88.md
new file mode 100644
index 0000000..a8d6214
--- /dev/null
+++ b/spec/block_docs/issue88.md
@@ -0,0 +1,19 @@
+HTML tags get chomped in list. See https://github.com/bhollis/maruku/issues/88
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<span> hello </span>
+
+1. <span> world </span>
+
+*** Output of inspect ***
+md_el(:document, [md_par(md_html("<span> hello </span>")),
+        md_el(:ol, md_li(md_html("<span> world </span>"), false))
+])
+*** Output of to_html ***
+<p><span> hello </span>
+</p>
+<ol>
+    <li><span> world </span>
+    </li>
+</ol>
\ No newline at end of file
diff --git a/spec/block_docs/issue89.md b/spec/block_docs/issue89.md
new file mode 100644
index 0000000..c922928
--- /dev/null
+++ b/spec/block_docs/issue89.md
@@ -0,0 +1,12 @@
+https://github.com/bhollis/maruku/issues/89 - Markdown extra .class ALD parsing error
+*** Parameters: ***
+{}
+*** Markdown input: ***
+
+[![Alt text](/Understanding-Big-Data-Cover-201x300.jpg){.alignright}](http://testsite.com/big-data)
+
+*** Output of inspect ***
+md_el(:document,
+  md_par(md_im_link(md_im_image("Alt text", "/Understanding-Big-Data-Cover-201x300.jpg", nil, [[:class, "alignright"]]), "http://testsite.com/big-data", nil)))
+*** Output of to_html ***
+<p><a href="http://testsite.com/big-data"><img class="alignright" src="/Understanding-Big-Data-Cover-201x300.jpg" alt="Alt text" /></a></p>
diff --git a/spec/block_docs/issue90.md b/spec/block_docs/issue90.md
new file mode 100644
index 0000000..8404159
--- /dev/null
+++ b/spec/block_docs/issue90.md
@@ -0,0 +1,38 @@
+https://github.com/bhollis/maruku/issues/90 - TOC not working without an H1 on the page.
+*** Parameters: ***
+{:use_numbered_headers => true}
+*** Markdown input: ***
+
+* Table of contents
+{:toc}
+
+## First Heading
+
+Foo
+
+## Second Heading
+
+### Subheading
+
+Foobar
+
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:ul, md_li("Table of contents", false), {}, [[:ref, "toc"]]),
+	md_el(:header, "First Heading", {:level=>2}),
+	md_par("Foo"),
+	md_el(:header, "Second Heading", {:level=>2}),
+	md_el(:header, "Subheading", {:level=>3}),
+	md_par("Foobar")
+],{},[])
+*** Output of to_html ***
+<div class="maruku_toc"><ul><li><span class="maruku_section_number">1. </span><a href="#first_heading">First Heading</a></li><li><span class="maruku_section_number">2. </span><a href="#second_heading">Second Heading</a><ul><li><span class="maruku_section_number">2.1. </span><a href="#subheading">Subheading</a></li></ul></li></ul></div>
+<h2 id="first_heading"><span class="maruku_section_number">1. </span>First Heading</h2>
+
+<p>Foo</p>
+
+<h2 id="second_heading"><span class="maruku_section_number">2. </span>Second Heading</h2>
+
+<h3 id="subheading"><span class="maruku_section_number">2.1. </span>Subheading</h3>
+
+<p>Foobar</p>
diff --git a/tests/unittest/pending/link.md b/spec/block_docs/link.md
similarity index 66%
rename from tests/unittest/pending/link.md
rename to spec/block_docs/link.md
index 6a715fd..53651e1 100644
--- a/tests/unittest/pending/link.md
+++ b/spec/block_docs/link.md
@@ -1,6 +1,6 @@
-Write a comment here
+
 *** Parameters: ***
-{} # params 
+{} # params
 *** Markdown input: ***
 <http://www.aa.com>
 
@@ -25,28 +25,28 @@ md_el(:document,[
 	md_par([md_url("http://www.bb.com")]),
 	md_par([md_url("http://www.cc.com")]),
 	md_par([md_url("http://www.dd.com")]),
-	md_el(:code,[],{:raw_code=>"<http://www.dd.com>"},[]),
+	md_el(:code,[],{:raw_code=>"<http://www.dd.com>", :lang=>nil},[]),
 	md_par([md_email("a at invalid.it")]),
 	md_par([md_email("a at invalid.it")]),
 	md_par([md_email("a at invalid.it")]),
-	md_el(:code,[],{:raw_code=>"<a at invalid.it>"},[])
+	md_el(:code,[],{:raw_code=>"<a at invalid.it>", :lang=>nil},[])
 ],{},[])
 *** Output of to_html ***
-<p><a href='http://www.aa.com'>http://www.aa.com</a></p>
+<p><a href="http://www.aa.com">http://www.aa.com</a></p>
 
-<p><a href='http://www.bb.com'>http://www.bb.com</a></p>
+<p><a href="http://www.bb.com">http://www.bb.com</a></p>
 
-<p><a href='http://www.cc.com'>http://www.cc.com</a></p>
+<p><a href="http://www.cc.com">http://www.cc.com</a></p>
 
-<p><a href='http://www.dd.com'>http://www.dd.com</a></p>
+<p><a href="http://www.dd.com">http://www.dd.com</a></p>
 
 <pre><code><http://www.dd.com></code></pre>
 
-<p><a href='mailto:a at invalid.it'>a@invalid.it</a></p>
+<p><a href="mailto:a at invalid.it">a@invalid.it</a></p>
 
-<p><a href='mailto:a at invalid.it'>a@invalid.it</a></p>
+<p><a href="mailto:a at invalid.it">a@invalid.it</a></p>
 
-<p><a href='mailto:a at invalid.it'>a@invalid.it</a></p>
+<p><a href="mailto:a at invalid.it">a@invalid.it</a></p>
 
 <pre><code><a at invalid.it></code></pre>
 *** Output of to_latex ***
@@ -67,18 +67,21 @@ md_el(:document,[
 
 \begin{verbatim}<a at invalid.it>\end{verbatim}
 *** Output of to_md ***
+<http://www.aa.com>
 
-*** Output of to_s ***
+ <http://www.bb.com>
 
-*** EOF ***
+  <http://www.cc.com>
 
+   <http://www.dd.com>
 
+    <http://www.dd.com>
 
-	OK!
+<a at invalid.it>
 
+ <a at invalid.it>
 
+   <a at invalid.it>
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+    <a at invalid.it>
+*** Output of to_s ***
diff --git a/tests/unittest/links.md b/spec/block_docs/links.md
similarity index 66%
rename from tests/unittest/links.md
rename to spec/block_docs/links.md
index f84f728..d1c9947 100644
--- a/tests/unittest/links.md
+++ b/spec/block_docs/links.md
@@ -27,6 +27,8 @@ If all else fails, ask [Google](http://www.google.com)
 
 And now [reference-style link ID with spaces] [Google Images]
 
+And now [reference-style link ID (without spaces)][Google Search]
+
 [google]: http://www.google.com
 
 [google2]: http://www.google.com 'Single quotes'
@@ -36,17 +38,17 @@ And now [reference-style link ID with spaces] [Google Images]
 [google4]: http://www.google.com (Parenthesis)
 
 [Google Search]: 
- http://www.google.com "Google search"
+ http://www.google.com 'Google search'
 
 [Google Images]: 
  http://images.google.com  (Google images)
 *** Output of inspect ***
 md_el(:document,[
+	md_par(["Search on ", md_link(["Google"],"")]),
+	md_par(["Search on ", md_link(["Google"],"")]),
 	md_par(["Search on ", md_link(["Google"],"google")]),
-	md_par(["Search on ", md_link(["Google"],"google")]),
-	md_par(["Search on ", md_link(["Google"],"google")]),
-	md_par(["Search on ", md_link(["Google"],"google")]),
-	md_par(["Search on ", md_link(["Google images"],"google_images")]),
+	md_par(["Search on ", md_link(["Google"],"Google")]),
+	md_par(["Search on ", md_link(["Google images"],"")]),
 	md_par(["Inline: ", md_im_link(["Google images"], "http://google.com", nil)]),
 	md_par([
 		"Inline with title: ",
@@ -71,37 +73,43 @@ md_el(:document,[
 	]),
 	md_par([
 		"And now ",
-		md_link(["reference-style link ID with spaces"],"google_images")
+		md_link(["reference-style link ID with spaces"],"Google Images")
+	]),
+	md_par([
+		"And now ",
+		md_link(["reference-style link ID (without spaces)"], "Google Search")
 	]),
 	md_ref_def("google", "http://www.google.com", {:title=>nil}),
 	md_ref_def("google2", "http://www.google.com", {:title=>"Single quotes"}),
 	md_ref_def("google3", "http://www.google.com", {:title=>"Double quotes"}),
 	md_ref_def("google4", "http://www.google.com", {:title=>"Parenthesis"}),
-	md_ref_def("google_search", "http://www.google.com", {:title=>"Google search"}),
-	md_ref_def("google_images", "http://images.google.com", {:title=>"Google images"})
+	md_ref_def("google search", "http://www.google.com", {:title=>"Google search"}),
+	md_ref_def("google images", "http://images.google.com", {:title=>"Google images"})
 ],{},[])
 *** Output of to_html ***
-<p>Search on <a href='http://www.google.com'>Google</a></p>
+<p>Search on <a href="http://www.google.com">Google</a></p>
 
-<p>Search on <a href='http://www.google.com'>Google</a></p>
+<p>Search on <a href="http://www.google.com">Google</a></p>
 
-<p>Search on <a href='http://www.google.com'>Google</a></p>
+<p>Search on <a href="http://www.google.com">Google</a></p>
 
-<p>Search on <a href='http://www.google.com'>Google</a></p>
+<p>Search on <a href="http://www.google.com">Google</a></p>
 
-<p>Search on <a href='http://images.google.com' title='Google images'>Google images</a></p>
+<p>Search on <a href="http://images.google.com" title="Google images">Google images</a></p>
 
-<p>Inline: <a href='http://google.com'>Google images</a></p>
+<p>Inline: <a href="http://google.com">Google images</a></p>
 
-<p>Inline with title: <a href='http://google.com' title='Title'>Google images</a></p>
+<p>Inline with title: <a href="http://google.com" title="Title">Google images</a></p>
 
-<p>Inline with title: <a href='http://google.com' title='Title'>Google images</a></p>
+<p>Inline with title: <a href="http://google.com" title="Title">Google images</a></p>
 
-<p>Search on <a href='http://www.gogole.com'>http://www.gogole.com</a> or <a href='http://Here.com'>http://Here.com</a> or ask <a href='mailto:bill at google.com'>bill@google.com</a> or you might ask bill at google.com.</p>
+<p>Search on <a href="http://www.gogole.com">http://www.gogole.com</a> or <a href="http://Here.com">http://Here.com</a> or ask <a href="mailto:bill at google.com">bill@google.com</a> or you might ask bill at google.com.</p>
 
-<p>If all else fails, ask <a href='http://www.google.com'>Google</a></p>
+<p>If all else fails, ask <a href="http://www.google.com">Google</a></p>
 
-<p>And now <a href='http://images.google.com' title='Google images'>reference-style link ID with spaces</a></p>
+<p>And now <a href="http://images.google.com" title="Google images">reference-style link ID with spaces</a></p>
+
+<p>And now <a href="http://www.google.com" title="Google search">reference-style link ID (without spaces)</a></p>
 *** Output of to_latex ***
 Search on \href{http://www.google.com}{Google}
 
@@ -124,6 +132,8 @@ Search on \href{http://www.gogole.com}{http\char58\char47\char47www\char46gogole
 If all else fails, ask \href{http://www.google.com}{Google}
 
 And now \href{http://images.google.com}{reference-style link ID with spaces}
+
+And now \href{http://www.google.com}{reference-style link ID (without spaces)}
 *** Output of to_md ***
 Search on Google
 
@@ -148,17 +158,8 @@ If all else fails, ask Google
 
 And now
 reference-style link ID with spaces
-*** Output of to_s ***
-Search on GoogleSearch on GoogleSearch on GoogleSearch on GoogleSearch on Google imagesInline: Google imagesInline with title: Google imagesInline with title: Google imagesSearch on  or  or ask  or you might ask bill at google.com.If all else fails, ask GoogleAnd now reference-style link ID with spaces
-*** EOF ***
-
-
-
-	OK!
 
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+And now
+reference-style link ID (without spaces)
+*** Output of to_s ***
+Search on GoogleSearch on GoogleSearch on GoogleSearch on GoogleSearch on Google imagesInline: Google imagesInline with title: Google imagesInline with title: Google imagesSearch on  or  or ask  or you might ask bill at google.com.If all else fails, ask GoogleAnd now reference-style link ID with spacesAnd now reference-style link ID (without spaces)
diff --git a/spec/block_docs/links2.md b/spec/block_docs/links2.md
new file mode 100644
index 0000000..281888e
--- /dev/null
+++ b/spec/block_docs/links2.md
@@ -0,0 +1,21 @@
+Write a comment here
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+See [foo' bar][foo_bar]
+
+[foo_bar]: http://agorf.gr/
+
+
+*** Output of inspect ***
+md_el(:document,[ md_par([ "See ", md_link(["foo", md_entity("rsquo"), " bar"],"foo_bar")]),
+	md_ref_def("foo_bar", "http://agorf.gr/", {:title=>nil})
+],{},[])
+*** Output of to_html ***
+<p>See <a href="http://agorf.gr/">foo’ bar</a></p>
+*** Output of to_latex ***
+See \href{http://agorf.gr/}{foo' bar}
+*** Output of to_md ***
+See foo bar
+*** Output of to_s ***
+See foo bar
diff --git a/tests/unittest/list1.md b/spec/block_docs/list1.md
similarity index 87%
rename from tests/unittest/list1.md
rename to spec/block_docs/list1.md
index 2ae2126..80cdb75 100644
--- a/tests/unittest/list1.md
+++ b/spec/block_docs/list1.md
@@ -44,15 +44,3 @@ This is a blockquote inside a list
 item.
 *** Output of to_s ***
 A list item with a blockquote:This is a blockquote inside a list item.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/list12.md b/spec/block_docs/list12.md
similarity index 63%
rename from tests/unittest/list12.md
rename to spec/block_docs/list12.md
index b48b241..3be8386 100644
--- a/tests/unittest/list12.md
+++ b/spec/block_docs/list12.md
@@ -9,13 +9,13 @@ Write a comment here
 *** Output of inspect ***
 md_el(:document,[
 	md_el(:ul,[
-		md_el(:li_span,[md_link(["Maruku"],"maruku"), ": good."],{:want_my_paragraph=>false},[])
+		md_el(:li,[md_link(["Maruku"],nil), ": good."],{:want_my_paragraph=>false},[])
 	],{},[]),
 	md_ref_def("maruku", "http://maruku.org/", {:title=>nil})
 ],{},[])
 *** Output of to_html ***
 <ul>
-<li><a href='http://maruku.org/'>Maruku</a>: good.</li>
+<li><a href="http://maruku.org/">Maruku</a>: good.</li>
 </ul>
 *** Output of to_latex ***
 \begin{itemize}%
@@ -26,15 +26,3 @@ md_el(:document,[
 -aruku: good.
 *** Output of to_s ***
 Maruku: good.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/list2.md b/spec/block_docs/list2.md
similarity index 76%
rename from tests/unittest/list2.md
rename to spec/block_docs/list2.md
index 85c72b4..06b013a 100644
--- a/tests/unittest/list2.md
+++ b/spec/block_docs/list2.md
@@ -29,7 +29,7 @@ md_el(:document,[
 <li>
 <p>This is a list item with two paragraphs.</p>
 
-<p>This is the second paragraph in the list item. You’re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
+<p>This is the second paragraph in the list item. You’re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
 </li>
 
 <li>
@@ -40,7 +40,7 @@ md_el(:document,[
 \begin{itemize}%
 \item This is a list item with two paragraphs.
 
-This is the second paragraph in the list item. You'{}re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+This is the second paragraph in the list item. You're only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
 
 
 \item other
@@ -54,15 +54,3 @@ This is the second paragraph in the list item. Youre only required to indent the
 -ther
 *** Output of to_s ***
 This is a list item with two paragraphs.This is the second paragraph in the list item. Youre only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.other
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/list_multipara.md b/spec/block_docs/list_multipara.md
new file mode 100644
index 0000000..d1cfad4
--- /dev/null
+++ b/spec/block_docs/list_multipara.md
@@ -0,0 +1,42 @@
+Lists with multiple paragraphs
+*** Parameters: ***
+{}
+*** Markdown input: ***
+*   A list item with a couple paragraphs,
+    each of which is indented.
+    
+    For example, this paragraph.
+
+*   Another list item
+*** Output of inspect ***
+md_el(:document, md_el(:ul, [
+	md_li([
+	  md_par("A list item with a couple paragraphs, each of which is indented."),
+	  md_par("For example, this paragraph.")
+  ], true),
+	md_li(md_par("Another list item"), false)
+]))
+*** Output of to_html ***
+<ul>
+<li>
+<p>A list item with a couple paragraphs, each of which is indented.</p>
+
+<p>For example, this paragraph.</p>
+</li>
+
+<li>
+<p>Another list item</p>
+</li>
+</ul>
+*** Output of to_latex ***
+\begin{itemize}%
+\item A list item with a couple paragraphs, each of which is indented.
+
+For example, this paragraph.
+
+
+\item Another list item
+
+
+
+\end{itemize}
diff --git a/tests/unittest/lists.md b/spec/block_docs/lists.md
similarity index 85%
rename from tests/unittest/lists.md
rename to spec/block_docs/lists.md
index dbc5a98..1ff85ac 100644
--- a/tests/unittest/lists.md
+++ b/spec/block_docs/lists.md
@@ -37,19 +37,19 @@ sit amet, consectetuer adipiscing elit.
 *** Output of inspect ***
 md_el(:document,[
 	md_el(:ul,[
-		md_el(:li_span,[
+		md_el(:li,[
 			"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[])
 	],{},[]),
@@ -111,7 +111,7 @@ md_el(:document,[
 <li>
 <p>This is a list item with two paragraphs.</p>
 
-<p>This is the second paragraph in the list item. You’re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
+<p>This is the second paragraph in the list item. You’re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
 </li>
 
 <li>
@@ -145,7 +145,7 @@ Ancora
 \begin{itemize}%
 \item This is a list item with two paragraphs.
 
-This is the second paragraph in the list item. You'{}re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+This is the second paragraph in the list item. You're only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
 
 
 \item Another item in the same list.
@@ -154,51 +154,50 @@ This is the second paragraph in the list item. You'{}re only required to indent
 
 \end{itemize}
 *** Output of to_md ***
--orem ipsum dolor sit amet,
+- Lorem ipsum dolor sit amet,
 consectetuer adipiscing elit.
 Aliquam hendrerit mi posuere
 lectus. Vestibulum enim wisi,
 viverra nec, fringilla in, laoreet
 vitae, risus.
--onec sit amet nisl. Aliquam semper
+- Donec sit amet nisl. Aliquam semper
 ipsum sit amet velit. Suspendisse
 id sem consectetuer libero luctus
 adipiscing.
--onec sit amet nisl. Aliquam semper
+- Donec sit amet nisl. Aliquam semper
 ipsum sit amet velit. Suspendisse
 id sem consectetuer libero luctus
 adipiscing.
--onec sit amet nisl. Aliquam semper
+- Donec sit amet nisl. Aliquam semper
 ipsum sit amet velit. Suspendisse
 id sem consectetuer libero luctus
 adipiscing.
--onec sit amet nisl. Aliquam semper
+- Donec sit amet nisl. Aliquam semper
 ipsum sit amet velit. Suspendisse
 id sem consectetuer libero luctus
 adipiscing.
 
 Ancora
 
--This is a list item with two paragraphs. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+- 
+This is a list item with two
+paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam
+hendrerit mi posuere lectus.
 ATTENZIONE!
--Suspendisse id sem consectetuer libero luctus adipiscing.
+- 
+Suspendisse id sem consectetuer libero
+luctus adipiscing.
 
 Ancora
 
--This is a list item with two paragraphs.
-This is the second paragraph in the list item. Youre only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
--nother item in the same list.
+- This is a list item with two
+paragraphs.
+  This is the second paragraph in the
+list item. You re only required to
+indent the first line. Lorem ipsum
+dolor sit amet, consectetuer adipiscing
+elit.
+- Another item in the same list.
 *** Output of to_s ***
 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing.Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing.Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero  [...]
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/lists10.md b/spec/block_docs/lists10.md
similarity index 68%
rename from tests/unittest/lists10.md
rename to spec/block_docs/lists10.md
index 18637d7..60cf8c2 100644
--- a/tests/unittest/lists10.md
+++ b/spec/block_docs/lists10.md
@@ -10,7 +10,7 @@ List:
 md_el(:document,[
 	md_par(["List:"]),
 	md_el(:ul,[
-		md_el(:li_span,["\303\250", md_code("gcc")],{:want_my_paragraph=>false},[])
+		md_el(:li,["è", md_code("gcc")],{:want_my_paragraph=>false},[])
 	],{},[])
 ],{},[])
 *** Output of to_html ***
@@ -29,18 +29,6 @@ List:
 *** Output of to_md ***
 List:
 
--�
+- è`gcc`
 *** Output of to_s ***
 List:è
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/loss.md b/spec/block_docs/lists11.md
similarity index 51%
rename from tests/unittest/loss.md
rename to spec/block_docs/lists11.md
index c8c64cd..ee0ed25 100644
--- a/tests/unittest/loss.md
+++ b/spec/block_docs/lists11.md
@@ -2,27 +2,22 @@ Write a comment here
 *** Parameters: ***
 {} # params 
 *** Markdown input: ***
-<br/>123
+- ένα
 
 *** Output of inspect ***
-md_el(:document,[md_html("<br />")],{},[])
+md_el(:document,[
+	md_el(:ul,[md_el(:li,["ένα"],{:want_my_paragraph=>false},[])],{},[])
+],{},[])
 *** Output of to_html ***
-<br />
+<ul>
+<li>ένα</li>
+</ul>
 *** Output of to_latex ***
+\begin{itemize}%
+\item ένα
 
+\end{itemize}
 *** Output of to_md ***
-
+- ένα
 *** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+ένα
diff --git a/spec/block_docs/lists12.md b/spec/block_docs/lists12.md
new file mode 100644
index 0000000..4e84887
--- /dev/null
+++ b/spec/block_docs/lists12.md
@@ -0,0 +1,43 @@
+List Items with non alphanumeric content. https://github.com/bhollis/maruku/issues/1
+*** Parameters: ***
+{}
+*** Markdown input: ***
+* A
+* ?
+* B
+
+*** Output of inspect ***
+md_el(:document,[
+  md_el(:ul,[
+    md_el(:li,["A"],{:want_my_paragraph=>false},[]),
+    md_el(:li,["?"],{:want_my_paragraph=>false},[]),
+    md_el(:li,["B"],{:want_my_paragraph=>false},[])
+  ],{},[])
+],{},[])
+
+*** Output of to_html ***
+<ul>
+<li>A</li>
+
+<li>?</li>
+
+<li>B</li>
+</ul>
+
+*** Output of to_latex ***
+\begin{itemize}%
+\item A
+\item ?
+\item B
+
+\end{itemize}
+
+*** Output of to_md ***
+- A
+- ?
+- B
+
+*** Output of to_s ***
+A?B
+
+
diff --git a/spec/block_docs/lists13.md b/spec/block_docs/lists13.md
new file mode 100644
index 0000000..af08c97
--- /dev/null
+++ b/spec/block_docs/lists13.md
@@ -0,0 +1,55 @@
+List Items with non alphanumeric content
+*** Parameters: ***
+{}
+*** Markdown input: ***
+* {: #foo} A
+* {: #bar } ?
+* {#fubar} B
+* {#fubar2 } C
+* {Not an IAL}
+
+*** Output of inspect ***
+md_el(:document,[
+  md_el(:ul,[
+   md_el(:li,["A"],{:want_my_paragraph=>false},[[:id, "foo"]]),
+   md_el(:li,["?"],{:want_my_paragraph=>false},[[:id, "bar"]]),
+   md_el(:li,["B"],{:want_my_paragraph=>false},[[:id, "fubar"]]),
+   md_el(:li,["C"],{:want_my_paragraph=>false},[[:id, "fubar2"]]),
+   md_el(:li,["{Not an IAL}"],{:want_my_paragraph=>false},[])
+   ],{},[]),
+],{},[])
+
+*** Output of to_html ***
+<ul>
+<li id="foo">A</li>
+
+<li id="bar">?</li>
+
+<li id="fubar">B</li>
+
+<li id="fubar2">C</li>
+
+<li>{Not an IAL}</li>
+</ul>
+
+*** Output of to_latex ***
+\begin{itemize}%
+\item A
+\item ?
+\item B
+\item C
+\item \{Not an IAL\}
+
+\end{itemize}
+
+*** Output of to_md ***
+- A
+- ?
+- B
+- C
+- {Not an IAL}
+
+*** Output of to_s ***
+A?BC{Not an IAL}
+
+
diff --git a/spec/block_docs/lists14.md b/spec/block_docs/lists14.md
new file mode 100644
index 0000000..006dc26
--- /dev/null
+++ b/spec/block_docs/lists14.md
@@ -0,0 +1,61 @@
+Nested Lists with IALs
+*** Parameters: ***
+{}
+*** Markdown input: ***
+1. First
+   * {: #bar} A
+   * B
+2. {: .foo} Second
+   * C
+   * D
+3. {:fubar style="color:red"} Third
+
+*** Output of inspect ***
+md_el(:document, [
+  md_el(:ol, [
+    md_li(["First",
+      md_el(:ul, [
+        md_li("A", false, [[:id, "bar"]]),
+        md_li("B", false)
+      ], {}, [])
+     ], false),
+    md_li([
+      "Second",
+      md_el(:ul, [md_li("C", false), md_li("D", false)],{},[])
+     ], false, [[:class, "foo"]]),
+    md_li("Third", false, [[:ref, "fubar"],["style", "color:red"]])
+   ],{},[])
+],{},[])
+
+*** Output of to_html ***
+<ol>
+<li>First
+<ul>
+<li id="bar">A</li>
+<li>B</li>
+</ul>
+</li>
+<li class="foo">Second
+<ul>
+<li>C</li>
+<li>D</li>
+</ul></li>
+<li style="color:red">Third</li>
+</ol>
+*** Output of to_latex ***
+\begin{enumerate}%
+\item First\begin{itemize}%
+\item A
+\item B
+
+\end{itemize}
+
+\item Second\begin{itemize}%
+\item C
+\item D
+
+\end{itemize}
+
+\item Third
+
+\end{enumerate}
diff --git a/spec/block_docs/lists15.md b/spec/block_docs/lists15.md
new file mode 100644
index 0000000..db39632
--- /dev/null
+++ b/spec/block_docs/lists15.md
@@ -0,0 +1,36 @@
+IAL following list
+*** Parameters: ***
+{}
+*** Markdown input: ***
+* First item
+* {#foo} Second item
+* Third item
+{:fubar style="color:red"}
+
+Now, a paragraph.
+*** Output of inspect ***
+md_el(:document, [
+  md_el(:ul, [
+    md_li("First item", false),
+    md_li("Second item", false, [[:id, "foo"]]),
+    md_li("Third item", false)
+  ], {}, []),
+  md_par("Now, a paragraph.")
+],{},[])
+
+*** Output of to_html ***
+<ul style="color:red">
+<li>First item</li>
+<li id="foo">Second item</li>
+<li>Third item</li>
+</ul>
+
+<p>Now, a paragraph.</p>
+*** Output of to_latex ***
+\begin{itemize}%
+\item First item
+\item Second item
+\item Third item
+
+\end{itemize}
+Now, a paragraph.
\ No newline at end of file
diff --git a/spec/block_docs/lists6.md b/spec/block_docs/lists6.md
new file mode 100644
index 0000000..a42ffaa
--- /dev/null
+++ b/spec/block_docs/lists6.md
@@ -0,0 +1,88 @@
+Maruku improperly wraps list elements in paragraphs and doesn't handle nested lists right.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+Here's another:
+
+1. First
+2. Second:
+	* Fee
+	* Fie
+	* Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+	* Fee
+	* Fie
+	* Foe
+
+3. Third
+
+*** Output of inspect ***
+md_el(:document,[
+ 	md_par(["Here", md_entity("rsquo"), "s another:"]),
+ 	md_el(:ol,[
+   	md_el(:li,["First"],{:want_my_paragraph=>false},[]),
+   	md_el(:li,[
+   	  "Second:",
+   	  md_el(:ul,[
+   	    md_el(:li,["Fee"],{:want_my_paragraph=>false},[]),
+ 	      md_el(:li,["Fie"],{:want_my_paragraph=>false},[]),
+ 	      md_el(:li,["Foe"],{:want_my_paragraph=>false},[])
+      ],{},[])
+    ],{:want_my_paragraph=>false},[]),
+ 	  md_el(:li,["Third"],{:want_my_paragraph=>false},[])
+  ],{},[]),
+ 	md_par(["Same thing but with paragraphs:"]),
+ 	md_el(:ol,[
+ 	  md_el(:li,[md_par("First")],{:want_my_paragraph=>true},[]),
+ 	  md_el(:li,[
+ 	    md_par("Second:"),
+ 	    md_el(:ul,[
+ 	      md_el(:li,["Fee"],{:want_my_paragraph=>false},[]),
+ 	      md_el(:li,["Fie"],{:want_my_paragraph=>false},[]),
+ 	      md_el(:li,["Foe"],{:want_my_paragraph=>false},[])
+      ],{},[])
+      ],{:want_my_paragraph=>true},[]),
+ 	  md_el(:li,md_par("Third"),{:want_my_paragraph=>false},[])
+  ],{},[])
+],{},[])
+*** Output of to_html ***
+<p>Here’s another:</p>
+
+<ol>
+<li>First</li>
+<li>Second:
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li>Third</li>
+</ol>
+
+<p>Same thing but with paragraphs:</p>
+
+<ol>
+<li><p>First</p></li>
+<li><p>Second:</p>
+
+<ul>
+<li>Fee</li>
+
+<li>Fie</li>
+
+<li>Foe</li>
+</ul></li>
+<li><p>Third</p></li>
+</ol>
+*** Output of to_latex ***
+
+*** Output of to_md ***
+
+*** Output of to_s ***
+
diff --git a/spec/block_docs/lists7b.md b/spec/block_docs/lists7b.md
new file mode 100644
index 0000000..2b2221c
--- /dev/null
+++ b/spec/block_docs/lists7b.md
@@ -0,0 +1,58 @@
+Test case given by Scott.
+
+http://rubyforge.org/tracker/index.php?func=detail&aid=8862&group_id=2795&atid=10735
+
+a should not be indented.
+
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+* a
+  * a1
+  * a2
+* b
+
+
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:ul,[
+		md_el(:li,[
+			"a",
+			md_el(:ul,[
+				md_el(:li,["a1"],{:want_my_paragraph=>false},[]),
+				md_el(:li,["a2"],{:want_my_paragraph=>false},[])
+			],{},[])
+		],{:want_my_paragraph=>false},[]),
+		md_el(:li,["b"],{:want_my_paragraph=>false},[])
+	],{},[])
+],{},[])
+*** Output of to_html ***
+<ul>
+<li>a
+<ul>
+<li>a1</li>
+
+<li>a2</li>
+</ul>
+</li>
+
+<li>b</li>
+</ul>
+
+*** Output of to_latex ***
+\begin{itemize}%
+\item a\begin{itemize}%
+\item a1
+\item a2
+
+\end{itemize}
+
+\item b
+
+\end{itemize}
+*** Output of to_md ***
+-* a1
+* a2
+-
+*** Output of to_s ***
+aa1a2b
diff --git a/spec/block_docs/lists9.md b/spec/block_docs/lists9.md
new file mode 100644
index 0000000..7ae1603
--- /dev/null
+++ b/spec/block_docs/lists9.md
@@ -0,0 +1,53 @@
+Maruku should not unnecessarily wrap <li>'s in <p>
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+- Due
+  1. tre
+  1. tre
+  1. tre
+- Due
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:ul,[
+		md_el(:li,[
+			"Due",
+			md_el(:ol,[
+				md_el(:li,["tre"],{:want_my_paragraph=>false},[]),
+				md_el(:li,["tre"],{:want_my_paragraph=>false},[]),
+				md_el(:li,["tre"],{:want_my_paragraph=>false},[])
+			],{},[])
+		],{:want_my_paragraph=>false},[]),
+		md_el(:li,["Due"],{:want_my_paragraph=>false},[])
+	],{},[])
+],{},[])
+*** Output of to_html ***
+<ul>
+<li>Due
+<ol>
+<li>tre</li>
+<li>tre</li>
+<li>tre</li>
+</ol></li>
+<li>Due</li>
+</ul>
+
+*** Output of to_latex ***
+\begin{itemize}%
+\item Due\begin{enumerate}%
+\item tre
+\item tre
+\item tre
+
+\end{enumerate}
+
+\item Due
+
+\end{itemize}
+*** Output of to_md ***
+-ue* tre
+* tre
+* tre
+-ue
+*** Output of to_s ***
+DuetretretreDue
diff --git a/tests/unittest/lists_after_paragraph.md b/spec/block_docs/lists_after_paragraph.md
similarity index 88%
rename from tests/unittest/lists_after_paragraph.md
rename to spec/block_docs/lists_after_paragraph.md
index e593c80..7a18717 100644
--- a/tests/unittest/lists_after_paragraph.md
+++ b/spec/block_docs/lists_after_paragraph.md
@@ -33,12 +33,12 @@ Paragraph with header:
 ### header ###
 
 Paragraph with header on two lines:
-header
-------
+header 2
+--------
 
 
 Paragraph with html after
-<div></div>
+<div>Woo</div>
 
 Paragraph with html after, indented:
      <em>Emphasis</em>
@@ -70,8 +70,9 @@ md_el(:document,[
 	md_par(["Paragraph with header:"]),
 	md_el(:header,["header"],{:level=>3},[]),
 	md_par(["Paragraph with header on two lines:"]),
-	md_el(:header,["header"],{:level=>2},[]),
-	md_par(["Paragraph with html after ", md_html("<div></div>")]),
+	md_el(:header,["header 2"],{:level=>2},[]),
+	md_par("Paragraph with html after"),
+  md_html("<div>Woo</div>"),
 	md_par([
 		"Paragraph with html after, indented: ",
 		md_html("<em>Emphasis</em>")
@@ -114,19 +115,20 @@ md_el(:document,[
 
 <p>Paragraph with header:</p>
 
-<h3 id='header'>header</h3>
+<h3 id="header">header</h3>
 
 <p>Paragraph with header on two lines:</p>
 
-<h2 id='header'>header</h2>
+<h2 id="header_2">header 2</h2>
 
-<p>Paragraph with html after <div /></p>
+<p>Paragraph with html after</p>
+<div>Woo</div>
 
 <p>Paragraph with html after, indented: <em>Emphasis</em></p>
 
 <p>Paragraph with html after, indented: <em>Emphasis</em> <em>tralla</em> <em>Emph</em></p>
 
-<p>Paragraph with html after, indented: <em>Emphasis *tralla* Emph</em></p>
+<p>Paragraph with html after, indented: <em>Emphasis <em>tralla</em> Emph</em></p>
 *** Output of to_latex ***
 Paragraph, list with no space: * ciao
 
@@ -157,9 +159,9 @@ Paragraph with header:
 
 Paragraph with header on two lines:
 
-\hypertarget{header}{}\subsection*{{header}}\label{header}
+\hypertarget{header_2}{}\subsection*{{header 2}}\label{header_2}
 
-Paragraph with html after 
+Paragraph with html after
 
 Paragraph with html after, indented: 
 
@@ -194,9 +196,13 @@ Quoted
 
 Paragraph with header:
 
-headerParagraph with header on two lines:
+### header
+
+Paragraph with header on two lines:
+
+## header
 
-headerParagraph with html after
+Paragraph with html after
 
 Paragraph with html after, indented:
 
@@ -206,15 +212,3 @@ tralla
 Paragraph with html after, indented:
 *** Output of to_s ***
 Paragraph, list with no space: * ciaoParagraph, list with 1 space: * ciaoParagraph, list with 3 space: * ciaoParagraph, list with 4 spaces: * ciaoParagraph, list with 1 tab: * ciaoParagraph (1 space after), list with no space: * ciaoParagraph (2 spaces after), list with no space:* ciaoParagraph (3 spaces after), list with no space: * ciaoParagraph with block quote:QuotedParagraph with header:headerParagraph with header on two lines:headerParagraph with html after Paragraph with html afte [...]
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/lists_blank.md b/spec/block_docs/lists_blank.md
new file mode 100644
index 0000000..a405451
--- /dev/null
+++ b/spec/block_docs/lists_blank.md
@@ -0,0 +1,35 @@
+Lists should allow newlines between items.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+*   A list item
+
+
+
+*   Another list item
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:ul,[
+    md_li(md_par("A list item"), true),
+    md_li(md_par("Another list item"), false)
+	])
+])
+*** Output of to_html ***
+<ul>
+<li>
+<p>A list item</p>
+</li>
+<li>
+<p>Another list item</p>
+</li>
+</ul>
+*** Output of to_latex ***
+\begin{itemize}%
+\item A list item
+
+
+\item Another list item
+
+
+
+\end{itemize}
diff --git a/tests/unittest/list3.md b/spec/block_docs/lists_blockquote_code.md
similarity index 85%
rename from tests/unittest/list3.md
rename to spec/block_docs/lists_blockquote_code.md
index 3f8f2b1..aa9d79f 100644
--- a/tests/unittest/list3.md
+++ b/spec/block_docs/lists_blockquote_code.md
@@ -1,4 +1,4 @@
-Write a comment abouth the test here.
+Lists should be able to contain blockquotes and code.
 *** Parameters: ***
 {}
 *** Markdown input: ***
@@ -19,7 +19,7 @@ md_el(:document,[
 		],{:want_my_paragraph=>true},[]),
 		md_el(:li,[
 			md_par(["A list item with a code block:"]),
-			md_el(:code,[],{:raw_code=>"<code goes here>"},[])
+			md_el(:code,[],{:raw_code=>"<code goes here>", :lang=>nil},[])
 		],{:want_my_paragraph=>true},[])
 	],{},[])
 ],{},[])
@@ -62,15 +62,3 @@ item.
 - list item with a code block:
 *** Output of to_s ***
 A list item with a blockquote:This is a blockquote inside a list item.A list item with a code block:
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/list4.md b/spec/block_docs/lists_need_blank_line.md
similarity index 63%
rename from tests/unittest/list4.md
rename to spec/block_docs/lists_need_blank_line.md
index 942aba1..242a958 100644
--- a/tests/unittest/list4.md
+++ b/spec/block_docs/lists_need_blank_line.md
@@ -1,39 +1,59 @@
-Write a comment abouth the test here.
+PENDING - list syntax needs a newline before it to be a valid list!
 *** Parameters: ***
 {}
 *** Markdown input: ***
+This is not a list:
+* one
+* two
+
 This is a list:
+
 * one
 * two
 
-This is not a list:
+This is a list:
+
 * one
 ciao
 
 This is a list:
+
 1. one
 1. two
 
-This is not a list:
+This is a list:
+
 1987. one
 ciao
 
+
 *** Output of inspect ***
 md_el(:document,[
+	md_par(["This is not a list:\n* one\n* two"]),
 	md_par(["This is a list:"]),
 	md_el(:ul,[
 		md_el(:li_span,["one"],{:want_my_paragraph=>false},[]),
 		md_el(:li_span,["two"],{:want_my_paragraph=>false},[])
 	],{},[]),
-	md_par(["This is not a list: * one ciao"]),
+	md_par(["This is a list:"]),
+  md_el(:ul,[
+		md_el(:li_span,["one ciao"],{:want_my_paragraph=>false},[])
+	],{},[]),
 	md_par(["This is a list:"]),
 	md_el(:ol,[
 		md_el(:li_span,["one"],{:want_my_paragraph=>false},[]),
 		md_el(:li_span,["two"],{:want_my_paragraph=>false},[])
 	],{},[]),
-	md_par(["This is not a list: 1987. one ciao"])
+  md_par(["This is a list:"]),
+	md_el(:ol,[
+    md_el(:li_span,["one ciao"],{:want_my_paragraph=>false},[])
+  ],{},[])
 ],{},[])
 *** Output of to_html ***
+<p>This is not a list:
+* one
+* two</p>
+
 <p>This is a list:</p>
 
 <ul>
@@ -42,7 +62,11 @@ md_el(:document,[
 <li>two</li>
 </ul>
 
-<p>This is not a list: * one ciao</p>
+<p>This is a list:</p>
+
+<ul>
+<li>one ciao</li>
+</ul>
 
 <p>This is a list:</p>
 
@@ -52,8 +76,16 @@ md_el(:document,[
 <li>two</li>
 </ol>
 
-<p>This is not a list: 1987. one ciao</p>
+<p>This is a list:</p>
+
+<ol>
+<li>one ciao</li>
+</ol>
 *** Output of to_latex ***
+This is not a list:
+* one
+* two
+
 This is a list:
 
 \begin{itemize}%
@@ -61,8 +93,12 @@ This is a list:
 \item two
 
 \end{itemize}
-This is not a list: * one ciao
+This is a list:
+
+\begin{itemize}%
+\item one ciao
 
+\end{itemize}
 This is a list:
 
 \begin{enumerate}%
@@ -70,7 +106,12 @@ This is a list:
 \item two
 
 \end{enumerate}
-This is not a list: 1987. one ciao
+This is a list:
+
+\begin{enumerate}%
+\item one ciao
+
+\end{enumerate}
 *** Output of to_md ***
 This is a list:
 
@@ -87,15 +128,3 @@ This is a list:
 This is not a list: 1987. one ciao
 *** Output of to_s ***
 This is a list:onetwoThis is not a list: * one ciaoThis is a list:onetwoThis is not a list: 1987. one ciao
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/lists_nested.md b/spec/block_docs/lists_nested.md
new file mode 100644
index 0000000..f4956de
--- /dev/null
+++ b/spec/block_docs/lists_nested.md
@@ -0,0 +1,44 @@
+Nesting lists.
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+*   A list item
+    * Foo
+    * Bar
+      * Bax
+      * Bap
+*   Another list item
+*** Output of inspect ***
+md_el(:document, md_el(:ul, [
+	md_li([
+	"A list item",
+	md_el(:ul, [
+	md_li("Foo", false),
+	md_li([
+	"Bar",
+	md_el(:ul, [
+	md_li("Bax", false),
+	md_li("Bap", false)
+])
+], false)
+])
+], false),
+	md_li("Another list item", false)
+]))
+*** Output of to_html ***
+<ul>
+<li>A list item
+<ul>
+<li>Foo</li>
+<li>Bar
+<ul>
+<li>Bax</li>
+
+<li>Bap</li>
+</ul>
+</li>
+</ul>
+</li>
+
+<li>Another list item</li>
+</ul>
diff --git a/spec/block_docs/lists_nested_blankline.md b/spec/block_docs/lists_nested_blankline.md
new file mode 100644
index 0000000..40860aa
--- /dev/null
+++ b/spec/block_docs/lists_nested_blankline.md
@@ -0,0 +1,34 @@
+Nesting lists should handle newlines inbetween list items.
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+* Bar
+  * Bax
+
+  * boo
+*** Output of inspect ***
+md_el(:document, md_el(:ul, [
+	md_li([
+	  md_par("Bar"),
+	  md_el(:ul, [
+	    md_li(md_par("Bax"), true),
+	    md_li(md_par("boo"), false)
+          ], {}, [])
+       ],true)
+],{},[]))
+*** Output of to_html ***
+<ul>
+<li>
+<p>Bar</p>
+
+<ul>
+<li>
+<p>Bax</p>
+</li>
+
+<li>
+<p>boo</p>
+</li>
+</ul>
+</li>
+</ul>
diff --git a/spec/block_docs/lists_nested_deep.md b/spec/block_docs/lists_nested_deep.md
new file mode 100644
index 0000000..d5c2a12
--- /dev/null
+++ b/spec/block_docs/lists_nested_deep.md
@@ -0,0 +1,43 @@
+Lists should be nestable to arbitrary depth.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+* Space
+  * Space
+    * Space
+      * Space
+        * Space
+
+*** Output of inspect ***
+md_el(:document, [
+	md_el(:ul, md_li([
+	"Space",
+	md_el(:ul, md_li([
+	"Space",
+	md_el(:ul, md_li([
+	"Space",
+	md_el(:ul, md_li(["Space", md_el(:ul, md_li("Space", false))], false))
+], false))
+], false))
+], false))
+])
+*** Output of to_html ***
+<ul>
+<li>Space
+<ul>
+<li>Space
+<ul>
+<li>Space
+<ul>
+<li>Space
+<ul>
+<li>Space</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
diff --git a/tests/unittest/lists_ol.md b/spec/block_docs/lists_ol.md
similarity index 82%
rename from tests/unittest/lists_ol.md
rename to spec/block_docs/lists_ol.md
index 9af6bcf..0bbafcb 100644
--- a/tests/unittest/lists_ol.md
+++ b/spec/block_docs/lists_ol.md
@@ -1,4 +1,4 @@
-Write a comment abouth the test here.
+PENDING - Maruku should handle weirdly indented lists and paragraphs within lists.
 *** Parameters: ***
 {}
 *** Markdown input: ***
@@ -44,19 +44,19 @@ sit amet, consectetuer adipiscing elit.
 *** Output of inspect ***
 md_el(:document,[
 	md_el(:ol,[
-		md_el(:li_span,[
+		md_el(:li,[
 			"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing."
 		],{:want_my_paragraph=>false},[])
 	],{},[]),
@@ -68,16 +68,15 @@ md_el(:document,[
 			]),
 			md_par(["ATTENZIONE!"]),
 			md_el(:ul,[
-				md_el(:li,[md_par(["Uno"])],{:want_my_paragraph=>false},[]),
-				md_el(:li,[
-					md_par(["Due"]),
+				md_el(:li,["Uno"],{:want_my_paragraph=>false},[]),
+				md_el(:li,["Due",
 					md_el(:ol,[
-						md_el(:li_span,["tre"],{:want_my_paragraph=>false},[]),
-						md_el(:li_span,["tre"],{:want_my_paragraph=>false},[]),
-						md_el(:li_span,["tre"],{:want_my_paragraph=>false},[])
-					],{},[])
-				],{:want_my_paragraph=>true},[]),
-				md_el(:li,[md_par(["Due"])],{:want_my_paragraph=>false},[])
+						md_el(:li,["tre"],{:want_my_paragraph=>false},[]),
+						md_el(:li,["tre"],{:want_my_paragraph=>false},[]),
+						md_el(:li,["tre"],{:want_my_paragraph=>false},[])
+					],{:want_my_paragraph=>false},[])
+				],{},[]),
+				md_el(:li,["Due"],{:want_my_paragraph=>false},[])
 			],{},[])
 		],{:want_my_paragraph=>true},[]),
 		md_el(:li,[
@@ -119,13 +118,9 @@ md_el(:document,[
 <p>ATTENZIONE!</p>
 
 <ul>
-<li>
-<p>Uno</p>
-</li>
-
-<li>
-<p>Due</p>
+<li>Uno</li>
 
+<li>Due
 <ol>
 <li>tre</li>
 
@@ -135,9 +130,7 @@ md_el(:document,[
 </ol>
 </li>
 
-<li>
-<p>Due</p>
-</li>
+<li>Due</li>
 </ul>
 </li>
 
@@ -152,7 +145,7 @@ md_el(:document,[
 <li>
 <p>This is a list item with two paragraphs.</p>
 
-<p>This is the second paragraph in the list item. You’re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
+<p>This is the second paragraph in the list item. You’re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
 </li>
 
 <li>
@@ -177,11 +170,7 @@ ATTENZIONE!
 
 \begin{itemize}%
 \item Uno
-
-
-\item Due
-
-\begin{enumerate}%
+\item Due\begin{enumerate}%
 \item tre
 \item tre
 \item tre
@@ -190,8 +179,6 @@ ATTENZIONE!
 
 \item Due
 
-
-
 \end{itemize}
 
 \item Suspendisse id sem consectetuer libero luctus adipiscing.
@@ -204,7 +191,7 @@ Ancora
 \begin{itemize}%
 \item This is a list item with two paragraphs.
 
-This is the second paragraph in the list item. You'{}re only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+This is the second paragraph in the list item. You're only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
 
 
 \item Another item in the same list.
@@ -238,37 +225,33 @@ This is the second paragraph in the list item. You'{}re only required to indent
 
 Ancora
 
-1.  
-    This is a list item with two paragraphs. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+1.
+    This is a list item with two
+    paragraphs. Lorem ipsum dolor sit amet,
+    consectetuer adipiscing elit. Aliquam
+    hendrerit mi posuere lectus.
     ATTENZIONE!
-    Uno
-    
-    Due
-    
+    - Uno
+    - Due
+
     1.  tre
     2.  tre
     3.  tre
-    
-    Due
-2.  
-    Suspendisse id sem consectetuer libero luctus adipiscing.
+    - Due
+2.
+    Suspendisse id sem consectetuer libero
+    luctus adipiscing.
 
 Ancora
 
--This is a list item with two paragraphs.
-This is the second paragraph in the list item. Youre only required to indent the first line. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
--nother item in the same list.
+-
+This is a list item with two
+paragraphs.
+This is the second paragraph in the
+list item. You re only required to
+indent the first line. Lorem ipsum
+dolor sit amet, consectetuer adipiscing
+elit.
+- Another item in the same list.
 *** Output of to_s ***
 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing.Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing.Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero  [...]
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/lists_paraindent.md b/spec/block_docs/lists_paraindent.md
new file mode 100644
index 0000000..8930d73
--- /dev/null
+++ b/spec/block_docs/lists_paraindent.md
@@ -0,0 +1,42 @@
+Indentation is weird...
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+*   A list item
+    * Foo
+    * Bar
+      * Bax
+    Bap
+*   Another list item
+*** Output of inspect ***
+md_el(:document, md_el(:ul, [
+	md_li([
+	"A list item",
+	md_el(:ul, [
+	md_li("Foo", false),
+	md_li([
+	"Bar",
+	md_el(:ul, [
+	md_li("Bax Bap", false)
+])
+], false)
+])
+], false),
+	md_li("Another list item", false)
+]))
+*** Output of to_html ***
+<ul>
+<li>A list item
+<ul>
+<li>Foo</li>
+
+<li>Bar
+<ul>
+<li>Bax Bap</li>
+</ul>
+</li>
+</ul>
+</li>
+
+<li>Another list item</li>
+</ul>
diff --git a/spec/block_docs/lists_tab.md b/spec/block_docs/lists_tab.md
new file mode 100644
index 0000000..09d9a18
--- /dev/null
+++ b/spec/block_docs/lists_tab.md
@@ -0,0 +1,54 @@
+Sub-lists should be indentable with a single tab.
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+Ciao
+
+*	Tab
+	*	Tab
+		*	Tab
+
+*** Output of inspect ***
+md_el(:document,[
+        md_par(["Ciao"]),
+        md_el(:ul,[md_el(:li,["Tab",
+          md_el(:ul,[md_el(:li,["Tab",
+            md_el(:ul,[md_el(:li,["Tab"],{:want_my_paragraph=>false})])],
+          {:want_my_paragraph=>false})])],
+        {:want_my_paragraph=>false})])
+       ])
+*** Output of to_html ***
+<p>Ciao</p>
+
+<ul>
+<li>Tab
+<ul>
+<li>Tab
+<ul>
+<li>Tab</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+*** Output of to_latex ***
+Ciao
+
+\begin{itemize}%
+\item Tab\begin{itemize}%
+\item Tab\begin{itemize}%
+\item Tab
+
+\end{itemize}
+
+
+\end{itemize}
+
+
+\end{itemize}
+*** Output of to_md ***
+Ciao
+
+-ab * Tab * Tab
+*** Output of to_s ***
+CiaoTab * Tab * Tab
diff --git a/spec/block_docs/loss.md b/spec/block_docs/loss.md
new file mode 100644
index 0000000..253fb94
--- /dev/null
+++ b/spec/block_docs/loss.md
@@ -0,0 +1,17 @@
+maruku treats all HTML as a block level element, but it should treat
+inline elements as part of a paragraph, even if they start the line.
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+<br/>123
+
+*** Output of inspect ***
+md_el(:document, md_par([md_html("<br />"), "123"]))
+*** Output of to_html ***
+<p><br/>123</p>
+*** Output of to_latex ***
+
+*** Output of to_md ***
+
+*** Output of to_s ***
+
diff --git a/spec/block_docs/math-blahtex/equations.md b/spec/block_docs/math-blahtex/equations.md
new file mode 100644
index 0000000..5544cc8
--- /dev/null
+++ b/spec/block_docs/math-blahtex/equations.md
@@ -0,0 +1,29 @@
+Write a comment here
+*** Parameters: ***
+require 'maruku/ext/math';{:html_math_engine => 'blahtex'}
+*** Markdown input: ***
+
+$$ x = y $$
+
+$$ x
+= y $$
+
+$$
+x = y $$
+
+$$ x = y
+$$
+
+*** Output of inspect ***
+
+*** Output of to_html ***
+<div class="maruku-equation"><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mrow><mi>x</mi><mo lspace='0.278em' rspace='0.278em'>=</mo><mi>y</mi></mrow>
+</math></div><div class="maruku-equation"><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mrow><mi>x</mi><mo lspace='0.278em' rspace='0.278em'>=</mo><mi>y</mi></mrow>
+</math></div><div class="maruku-equation"><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mrow><mi>x</mi><mo lspace='0.278em' rspace='0.278em'>=</mo><mi>y</mi></mrow>
+</math></div><div class="maruku-equation"><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mrow><mi>x</mi><mo lspace='0.278em' rspace='0.278em'>=</mo><mi>y</mi></mrow>
+</math></div>
+*** Output of to_latex ***
diff --git a/spec/block_docs/math-blahtex/inline.md b/spec/block_docs/math-blahtex/inline.md
new file mode 100644
index 0000000..21c9c59
--- /dev/null
+++ b/spec/block_docs/math-blahtex/inline.md
@@ -0,0 +1,48 @@
+
+*** Parameters: ***
+require 'maruku/ext/math'; {:html_math_engine => 'blahtex'}
+*** Markdown input: ***
+Here are some formulas:
+
+*	$\alpha$
+*	$x^{n}+y^{n} \neq z^{n}$
+
+That's it, nothing else is supported.
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["Here are some formulas:"]),
+	md_el(:ul,[
+		md_el(:li,[md_el(:inline_math,[],{:math=>"\\alpha"},[])],{:want_my_paragraph=>false},[]),
+		md_el(:li,[md_el(:inline_math,[],{:math=>"x^{n}+y^{n} \\neq z^{n}"},[])],{:want_my_paragraph=>false},[])
+	],{},[]),
+	md_par(["That", md_entity("rsquo"), "s it, nothing else is supported."])
+],{},[])
+*** Output of to_html ***
+<p>Here are some formulas:</p>
+
+<ul>
+<li><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><mi>α</mi></math></li>
+
+<li><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml">
+<mrow><msup><mi>x</mi><mi>n</mi></msup><mo lspace="0.222em" rspace="0.222em">+</mo><msup><mi>y</mi><mi>n</mi></msup><mo lspace="0.278em" rspace="0.278em">&#x2260;</mo><msup><mi>z</mi><mi>n</mi></msup></mrow>
+</math></li>
+</ul>
+
+<p>That’s it, nothing else is supported.</p>
+*** Output of to_latex ***
+Here are some formulas:
+
+\begin{itemize}%
+\item $\alpha$
+\item $x^{n}+y^{n} \neq z^{n}$
+
+\end{itemize}
+That's it, nothing else is supported.
+*** Output of to_md ***
+Here are some formulas:
+
+--
+That s it, nothing else is supported.
+*** Output of to_s ***
+Here are some formulas:Thats it, nothing else is supported.
diff --git a/spec/block_docs/math-blahtex/math2.md b/spec/block_docs/math-blahtex/math2.md
new file mode 100644
index 0000000..4e9a378
--- /dev/null
+++ b/spec/block_docs/math-blahtex/math2.md
@@ -0,0 +1,52 @@
+
+*** Parameters: ***
+require 'maruku/ext/math'
+{:math_numbered => ['\\['], :html_math_engine => 'blahtex' }
+*** Markdown input: ***
+
+\[
+	\alpha
+\]
+
+\begin{equation}
+	\alpha
+\end{equation}
+
+\begin{equation} \beta
+\end{equation}
+
+
+\begin{equation} \gamma \end{equation}
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:equation,[],{:label=>"eq1",:math=>"\n\t\\alpha\n\n",:num=>1},[]),
+	md_el(:equation,[],{:label=>nil,:math=>"\n\t\\alpha\n\n",:num=>nil},[]),
+	md_el(:equation,[],{:label=>nil,:math=>" \\beta\n\n",:num=>nil},[]),
+	md_el(:equation,[],{:label=>nil,:math=>" \\gamma ",:num=>nil},[])
+],{},[])
+*** Output of to_html ***
+<div class="maruku-equation" id="eq:eq1"><span class="maruku-eq-number">(1)</span><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mi>&#x3b1;</mi>
+</math></div><div class="maruku-equation"><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mi>&#x3b1;</mi>
+</math></div><div class="maruku-equation"><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mi>&#x3b2;</mi>
+</math></div><div class="maruku-equation"><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'>
+<mi>&#x3b3;</mi>
+</math></div>
+*** Output of to_latex ***
+\begin{equation}
+\alpha
+\label{eq1}\end{equation}
+\begin{displaymath}
+\alpha
+\end{displaymath}
+\begin{displaymath}
+\beta
+\end{displaymath}
+\begin{displaymath}
+\gamma
+\end{displaymath}
+*** Output of to_md ***
+
+*** Output of to_s ***
diff --git a/spec/block_docs/math-blahtex/table.md b/spec/block_docs/math-blahtex/table.md
new file mode 100644
index 0000000..80c191d
--- /dev/null
+++ b/spec/block_docs/math-blahtex/table.md
@@ -0,0 +1,25 @@
+Write a comment here
+*** Parameters: ***
+require 'maruku/ext/math';{:html_math_engine => 'blahtex' }
+*** Markdown input: ***
+<table markdown='1'>
+	$\alpha$
+	<thead>
+		<td markdown='1'>$\beta$</td>
+	</thead>
+</table>
+*** Output of inspect ***
+md_el(:document,[
+	md_html("<table markdown='1'>\n\t$\\alpha$\n\t<thead>\n\t\t<td markdown='1'>$\\beta$</td>\n\t</thead>\n</table>")
+],{},[])
+*** Output of to_html ***
+<table><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><mi>α</mi></math><thead>
+		<td><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><mi>β</mi></math></td>
+	</thead>
+</table>
+*** Output of to_latex ***
+
+*** Output of to_md ***
+
+*** Output of to_s ***
+
diff --git a/spec/block_docs/math/embedded_invalid_svg.md b/spec/block_docs/math/embedded_invalid_svg.md
new file mode 100644
index 0000000..62bfa11
--- /dev/null
+++ b/spec/block_docs/math/embedded_invalid_svg.md
@@ -0,0 +1,108 @@
+REXML PENDING - This tests that invalid SVG within LaTeX gets corrected and still output. I'm not sure why it should do that.
+Pending because Nokogiri will handle the tagsoup but REXML won't.
+TODO: The LaTeX output does not look correct here!
+*** Parameters: ***
+require 'maruku/ext/math'; {:html_math_engine => 'itex2mml'}
+*** Markdown input: ***
+ In $SU(3)$, $\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <g></rect>
+</svg>
+\end{svg}\includegraphics[width=2em]{young1}
+ \otimes
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 20 16">
+  <desc>Fundamental Representation</desc>
+  <g>
+</svg>
+\end{svg}\includegraphics[width=1em]{young2}
+ =
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="26" viewBox="0 0 30 26">
+  <desc>Adjoint Representation</desc>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=2em]{young3}
+ \oplus
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="40" height="16" viewBox="0 0 40 16">
+  <desc>Rank-3 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+    <rect width="10" height="10" x="10"/>
+    <rect width="10" height="10" x="20"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=3em]{young4}$.
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["In ",
+	  md_el(:inline_math, [], {:math=>"SU(3)"}),
+	  ", ",
+	  md_el(:inline_math, [], {:math=>"\\begin{svg}\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"16\" viewBox=\"0 0 30 16\">\n  <g></rect>\n</svg>\n\\end{svg}\\includegraphics[width=2em]{young1}\n \\otimes\n\\begin{svg}\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"16\" viewBox=\"0 0 20 16\">\n  <desc>Fundamental Representation</desc>\n  <g>\n</svg>\n\\end{svg}\\includegraphics[width=1em]{young2}\n =\n\\begin{svg}\n<svg xmlns=\"http://www.w3.org/2000/s [...]
+	  "."
+	  ])
+],{},[])
+*** Output of to_html ***
+<p>In <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><mi>SU</mi><mo stretchy="false">(</mo><mn>3</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">SU(3)</annotation></semantics></math>, <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <g></g>
+</svg>
+</annotation-xml></semantics><mo>⊗</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 20 16">
+  <desc>Fundamental Representation</desc>
+  <g>
+</g>
+</svg></annotation-xml><mo>=</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="26" viewBox="0 0 30 26">
+  <desc>Adjoint Representation</desc>
+  </svg>
+</annotation-xml>
+</semantics></semantics><mo>⊕</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="40" height="16" viewBox="0 0 40 16">
+  <desc>Rank-3 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+    <rect width="10" height="10" x="20"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics></mrow><annotation encoding="application/x-tex">\begin{svg}
+svg xmlns=http://www.w3.org/2000/svg width=30 height=16 viewBox=0 0 30 16
+  g/rect
+/svg
+\end{svg}\includegraphics[width=2em]{young1}
+ \otimes
+\begin{svg}
+svg xmlns=http://www.w3.org/2000/svg width=20 height=16 viewBox=0 0 20 16
+  descFundamental Representation/desc
+  g
+/svg
+\end{svg}\includegraphics[width=1em]{young2}
+ =
+\begin{svg}
+svg xmlns=http://www.w3.org/2000/svg width=30 height=26 viewBox=0 0 30 26
+  descAdjoint Representation/desc
+  /g
+/svg
+\end{svg}\includegraphics[width=2em]{young3}
+ \oplus
+\begin{svg}
+svg xmlns=http://www.w3.org/2000/svg width=40 height=16 viewBox=0 0 40 16
+  descRank-3 Symmetric Tensor Representation/desc
+  g transform=translate(5,5) fill=#FCC stroke=#000 stroke-width=2
+    rect width=10 height=10/
+    rect width=10 height=10 x=10/
+    rect width=10 height=10 x=20/
+  /g
+/svg
+\end{svg}\includegraphics[width=3em]{young4}</annotation></semantics></math>.</p>
+*** Output of to_latex ***
+In $SU(3)$, $ \includegraphics[width=2em]{young1}
+ \otimes
+ \includegraphics[width=1em]{young2}
+ =
+ \includegraphics[width=2em]{young3}
+ \oplus
+ \includegraphics[width=3em]{young4}$.
diff --git a/spec/block_docs/math/embedded_svg.md b/spec/block_docs/math/embedded_svg.md
new file mode 100644
index 0000000..d84f87a
--- /dev/null
+++ b/spec/block_docs/math/embedded_svg.md
@@ -0,0 +1,136 @@
+Support embedded SVG in LaTeX expressions.
+TODO: The LaTeX output does not look correct here!
+*** Parameters: ***
+require 'maruku/ext/math'; {:html_math_engine => 'itex2mml'}
+*** Markdown input: ***
+ In $SU(3)$, $\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+    <rect width="10" height="10" x="10"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=2em]{young1}
+ \otimes
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 20 16">
+  <desc>Fundamental Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=1em]{young2}
+ =
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="26" viewBox="0 0 30 26">
+  <desc>Adjoint Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+    <rect width="10" height="10" x="10"/>
+    <rect width="10" height="10" y="10"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=2em]{young3}
+ \oplus
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="40" height="16" viewBox="0 0 40 16">
+  <desc>Rank-3 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+    <rect width="10" height="10" x="10"/>
+    <rect width="10" height="10" x="20"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=3em]{young4}$.
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["In ",
+	  md_el(:inline_math, [], {:math=>"SU(3)"}),
+	  ", ",
+	  md_el(:inline_math, [], {:math=>"\\begin{svg}\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"16\" viewBox=\"0 0 30 16\">\n  <desc>Rank-2 Symmetric Tensor Representation</desc>\n  <g transform=\"translate(5,5)\" fill=\"#FCC\" stroke=\"#000\" stroke-width=\"2\">\n    <rect width=\"10\" height=\"10\"/>\n    <rect width=\"10\" height=\"10\" x=\"10\"/>\n  </g>\n</svg>\n\\end{svg}\\includegraphics[width=2em]{young1}\n \\otimes\n\\begin{svg}\n<svg xmlns=\"http://www.w3.org/ [...]
+	  "."
+	  ])
+],{},[])
+*** Output of to_html ***
+<p>In <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><mi>SU</mi><mo stretchy="false">(</mo><mn>3</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">SU(3)</annotation></semantics></math>, <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics><mo>⊗</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 20 16">
+  <desc>Fundamental Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics><mo>=</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="26" viewBox="0 0 30 26">
+  <desc>Adjoint Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+    <rect width="10" height="10" y="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics><mo>⊕</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="40" height="16" viewBox="0 0 40 16">
+  <desc>Rank-3 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+    <rect width="10" height="10" x="20"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics></mrow><annotation encoding="application/x-tex">\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+    <rect width="10" height="10" x="10"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=2em]{young1}
+ \otimes
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="16" viewBox="0 0 20 16">
+  <desc>Fundamental Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=1em]{young2}
+ =
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="26" viewBox="0 0 30 26">
+  <desc>Adjoint Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+    <rect width="10" height="10" x="10"/>
+    <rect width="10" height="10" y="10"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=2em]{young3}
+ \oplus
+\begin{svg}
+<svg xmlns="http://www.w3.org/2000/svg" width="40" height="16" viewBox="0 0 40 16">
+  <desc>Rank-3 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"/>
+    <rect width="10" height="10" x="10"/>
+    <rect width="10" height="10" x="20"/>
+  </g>
+</svg>
+\end{svg}\includegraphics[width=3em]{young4}</annotation></semantics></math>.</p>
+*** Output of to_latex ***
+In $SU(3)$, $ \includegraphics[width=2em]{young1}
+ \otimes
+ \includegraphics[width=1em]{young2}
+ =
+ \includegraphics[width=2em]{young3}
+ \oplus
+ \includegraphics[width=3em]{young4}$.
diff --git a/spec/block_docs/math/equations.md b/spec/block_docs/math/equations.md
new file mode 100644
index 0000000..24c34c6
--- /dev/null
+++ b/spec/block_docs/math/equations.md
@@ -0,0 +1,49 @@
+Write a comment here
+*** Parameters: ***
+require 'maruku/ext/math';{:html_math_engine => 'itex2mml'}
+*** Markdown input: ***
+
+$$ x = y $$
+
+$$ x 
+= y $$
+
+$$ 
+x = y $$
+
+$$ x = y 
+$$
+
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:equation,[],{:label=>nil,:math=>" x = y ",:num=>nil},[]),
+	md_el(:equation,[],{:label=>nil,:math=>" x \n= y \n",:num=>nil},[]),
+	md_el(:equation,[],{:label=>nil,:math=>" \nx = y \n",:num=>nil},[]),
+	md_el(:equation,[],{:label=>nil,:math=>" x = y \n\n",:num=>nil},[])
+],{},[])
+*** Output of to_html ***
+<div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>x</mi><mo>=</mo><mi>y</mi></mrow><annotation encoding="application/x-tex"> x = y </annotation></semantics></math></div><div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>x</mi><mo>=</mo><mi>y</mi></mrow><annotation encoding="application/x-tex"> x 
+= y 
+</annotation></semantics></math></div><div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>x</mi><mo>=</mo><mi>y</mi></mrow><annotation encoding="application/x-tex"> 
+x = y 
+</annotation></semantics></math></div><div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>x</mi><mo>=</mo><mi>y</mi></mrow><annotation encoding="application/x-tex"> x = y 
+
+</annotation></semantics></math></div>
+*** Output of to_latex ***
+\begin{displaymath}
+x = y
+\end{displaymath}
+\begin{displaymath}
+x 
+= y
+\end{displaymath}
+\begin{displaymath}
+x = y
+\end{displaymath}
+\begin{displaymath}
+x = y
+\end{displaymath}
+*** Output of to_md ***
+
+*** Output of to_s ***
+
diff --git a/spec/block_docs/math/inline.md b/spec/block_docs/math/inline.md
new file mode 100644
index 0000000..579c114
--- /dev/null
+++ b/spec/block_docs/math/inline.md
@@ -0,0 +1,46 @@
+
+*** Parameters: ***
+require 'maruku/ext/math'; {:html_math_engine => 'itex2mml'}
+*** Markdown input: ***
+Here are some formulas:
+
+*	$\alpha$
+*	$x^{n}+y^{n} \neq z^{n}$
+
+That's it, nothing else is supported.
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["Here are some formulas:"]),
+	md_el(:ul,[
+		md_el(:li,[md_el(:inline_math,[],{:math=>"\\alpha"},[])],{:want_my_paragraph=>false},[]),
+		md_el(:li,[md_el(:inline_math,[],{:math=>"x^{n}+y^{n} \\neq z^{n}"},[])],{:want_my_paragraph=>false},[])
+	],{},[]),
+	md_par(["That", md_entity("rsquo"), "s it, nothing else is supported."])
+],{},[])
+*** Output of to_html ***
+<p>Here are some formulas:</p>
+
+<ul>
+<li><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></li>
+
+<li><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><msup><mi>x</mi> <mi>n</mi></msup><mo>+</mo><msup><mi>y</mi> <mi>n</mi></msup><mo>≠</mo><msup><mi>z</mi> <mi>n</mi></msup></mrow><annotation encoding="application/x-tex">x^{n}+y^{n} \neq z^{n}</annotation></semantics></math></li>
+</ul>
+
+<p>That’s it, nothing else is supported.</p>
+*** Output of to_latex ***
+Here are some formulas:
+
+\begin{itemize}%
+\item $\alpha$
+\item $x^{n}+y^{n} \neq z^{n}$
+
+\end{itemize}
+That's it, nothing else is supported.
+*** Output of to_md ***
+Here are some formulas:
+
+--
+That s it, nothing else is supported.
+*** Output of to_s ***
+Here are some formulas:Thats it, nothing else is supported.
diff --git a/spec/block_docs/math/math2.md b/spec/block_docs/math/math2.md
new file mode 100644
index 0000000..0417b34
--- /dev/null
+++ b/spec/block_docs/math/math2.md
@@ -0,0 +1,53 @@
+
+*** Parameters: ***
+require 'maruku/ext/math'
+{:math_numbered => ['\\['], :html_math_engine => 'itex2mml' }
+*** Markdown input: ***
+
+\[
+	\alpha
+\]
+
+\begin{equation}
+	\alpha
+\end{equation}
+
+\begin{equation} \beta
+\end{equation}
+
+
+\begin{equation} \gamma \end{equation}
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:equation,[],{:label=>"eq1",:math=>"\n\t\\alpha\n\n",:num=>1},[]),
+	md_el(:equation,[],{:label=>nil,:math=>"\n\t\\alpha\n\n",:num=>nil},[]),
+	md_el(:equation,[],{:label=>nil,:math=>" \\beta\n\n",:num=>nil},[]),
+	md_el(:equation,[],{:label=>nil,:math=>" \\gamma ",:num=>nil},[])
+],{},[])
+*** Output of to_html ***
+<div class="maruku-equation" id="eq:eq1"><span class="maruku-eq-number">(1)</span><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">
+	\alpha
+
+</annotation></semantics></math></div><div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">
+	\alpha
+
+</annotation></semantics></math></div><div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>β</mi></mrow><annotation encoding="application/x-tex"> \beta
+
+</annotation></semantics></math></div><div class="maruku-equation"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><mrow><mi>γ</mi></mrow><annotation encoding="application/x-tex"> \gamma </annotation></semantics></math></div>
+*** Output of to_latex ***
+\begin{equation}
+\alpha
+\label{eq1}\end{equation}
+\begin{displaymath}
+\alpha
+\end{displaymath}
+\begin{displaymath}
+\beta
+\end{displaymath}
+\begin{displaymath}
+\gamma
+\end{displaymath}
+*** Output of to_md ***
+
+*** Output of to_s ***
+
diff --git a/tests/unittest/math/notmath.md b/spec/block_docs/math/notmath.md
similarity index 79%
rename from tests/unittest/math/notmath.md
rename to spec/block_docs/math/notmath.md
index 4d66902..81a6146 100644
--- a/tests/unittest/math/notmath.md
+++ b/spec/block_docs/math/notmath.md
@@ -23,15 +23,3 @@ This is not $math$.
 [ \alpha ]
 *** Output of to_s ***
 This is not $math$.[ \alpha ]
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/math/raw_mathml.md b/spec/block_docs/math/raw_mathml.md
new file mode 100644
index 0000000..9674d46
--- /dev/null
+++ b/spec/block_docs/math/raw_mathml.md
@@ -0,0 +1,87 @@
+JRUBY NOKOGIRI PENDING - MathML inline with HTML
+(JRuby Nokogiri is broken for empty tags: https://github.com/sparklemotion/nokogiri/issues/971)
+*** Parameters: ***
+{}
+*** Markdown input: ***
+In <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><mi>SU</mi><mo stretchy="false">(</mo><mn>3</mn><mo stretchy="false">)</mo></math>, <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics><mo>=</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics></math>.
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics><mo>=</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics></math>
+
+*** Output of inspect ***
+md_el(:document,[
+	md_par(["In ",
+	  md_html("<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"inline\" class=\"maruku-mathml\"><mi>SU</mi><mo stretchy=\"false\">(</mo><mn>3</mn><mo stretchy=\"false\">)</mo></math>"),
+	  ", ",
+	  md_html("<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"inline\" class=\"maruku-mathml\"><semantics><annotation-xml encoding=\"SVG1.1\">\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"16\" viewBox=\"0 0 30 16\">\n  <desc>Rank-2 Symmetric Tensor Representation</desc>\n  <g transform=\"translate(5,5)\" fill=\"#FCC\" stroke=\"#000\" stroke-width=\"2\">\n    <rect width=\"10\" height=\"10\"></rect>\n    <rect width=\"10\" height=\"10\" x=\"10\"></rect>\n  < [...]
+	  "."
+	  ]),
+	  md_html("<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\" class=\"maruku-mathml\"><semantics><annotation-xml encoding=\"SVG1.1\">\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"16\" viewBox=\"0 0 30 16\">\n  <desc>Rank-2 Symmetric Tensor Representation</desc>\n  <g transform=\"translate(5,5)\" fill=\"#FCC\" stroke=\"#000\" stroke-width=\"2\">\n    <rect width=\"10\" height=\"10\"></rect>\n    <rect width=\"10\" height=\"10\" x=\"10\"></rect>\n  </ [...]
+],{},[])
+*** Output of to_html ***
+<p>In <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><mi>SU</mi><mo stretchy="false">(</mo><mn>3</mn><mo stretchy="false">)</mo></math>, <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics><mo>=</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics></math>.</p>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="maruku-mathml"><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics><mo>=</mo><semantics><annotation-xml encoding="SVG1.1">
+<svg xmlns="http://www.w3.org/2000/svg" width="30" height="16" viewBox="0 0 30 16">
+  <desc>Rank-2 Symmetric Tensor Representation</desc>
+  <g transform="translate(5,5)" fill="#FCC" stroke="#000" stroke-width="2">
+    <rect width="10" height="10"></rect>
+    <rect width="10" height="10" x="10"></rect>
+  </g>
+</svg>
+</annotation-xml></semantics></math>
diff --git a/spec/block_docs/math/spaces_after_inline_math.md b/spec/block_docs/math/spaces_after_inline_math.md
new file mode 100644
index 0000000..f081b0b
--- /dev/null
+++ b/spec/block_docs/math/spaces_after_inline_math.md
@@ -0,0 +1,17 @@
+
+*** Parameters: ***
+require 'maruku/ext/math'; {:html_math_engine => 'itex2mml'}
+*** Markdown input: ***
+This *is* $a * b * c$ ahem.
+*** Output of inspect ***
+md_el(:document, md_par([
+        "This ",
+        md_em("is"),
+        " ",
+        md_el(:inline_math, [], {:math=>"a * b * c"}),
+        " ahem."
+]))
+*** Output of to_html ***
+<p>This <em>is</em> <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><mi>a</mi><mo>*</mo><mi>b</mi><mo>*</mo><mi>c</mi></mrow><annotation encoding="application/x-tex">a * b * c</annotation></semantics></math> ahem.</p>
+*** Output of to_latex ***
+This \emph{is} $a * b * c$ ahem.
diff --git a/spec/block_docs/math/table.md b/spec/block_docs/math/table.md
new file mode 100644
index 0000000..3e7e2a8
--- /dev/null
+++ b/spec/block_docs/math/table.md
@@ -0,0 +1,25 @@
+Write a comment here
+*** Parameters: ***
+require 'maruku/ext/math';{:html_math_engine => 'itex2mml' }
+*** Markdown input: ***
+<table markdown='1'>
+	$\alpha$
+	<thead>
+		<td markdown='1'>$\beta$</td>
+	</thead>
+</table>
+*** Output of inspect ***
+md_el(:document,[
+	md_html("<table markdown='1'>\n\t$\\alpha$\n\t<thead>\n\t\t<td markdown='1'>$\\beta$</td>\n\t</thead>\n</table>")
+],{},[])
+*** Output of to_html ***
+<table><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math><thead>
+		<td><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline" class="maruku-mathml"><semantics><mrow><mi>β</mi></mrow><annotation encoding="application/x-tex">\beta</annotation></semantics></math></td>
+	</thead>
+</table>
+*** Output of to_latex ***
+
+*** Output of to_md ***
+
+*** Output of to_s ***
+
diff --git a/tests/unittest/math/table2.md b/spec/block_docs/math/table2.md
similarity index 52%
rename from tests/unittest/math/table2.md
rename to spec/block_docs/math/table2.md
index 3b72cc7..10ef5be 100644
--- a/tests/unittest/math/table2.md
+++ b/spec/block_docs/math/table2.md
@@ -1,4 +1,4 @@
-Write a comment here
+
 *** Parameters: ***
 {}
 *** Markdown input: ***
@@ -13,42 +13,30 @@ Write a comment here
 *** Output of inspect ***
 md_el(:document,[
 	md_el(:table,[
-		md_el(:head_cell,["Symbol"],{},[]),
+		[md_el(:head_cell,["Symbol"],{},[]),
 		md_el(:head_cell,["Meaning"],{},[]),
-		md_el(:head_cell,["comments"],{},[]),
-		md_el(:cell,[" ", md_entity("alpha")],{},[[:ref, "r"]]),
+		md_el(:head_cell,["comments"],{},[])],
+		[md_el(:cell,[" ", md_entity("alpha")],{},[[:ref, "r"]]),
 		md_el(:cell,["The first"],{},[]),
-		md_el(:cell,["I like it."],{},[]),
-		md_el(:cell,[" ", md_entity("aleph")],{},[[:ref, "r"]]),
+		md_el(:cell,["I like it."],{},[])],
+		[md_el(:cell,[" ", md_entity("aleph")],{},[[:ref, "r"]]),
 		md_el(:cell,["The first"],{},[]),
-		md_el(:cell,["I like it."],{},[])
+		md_el(:cell,["I like it."],{},[])]
 	],{:align=>[:left, :left, :left]},[]),
 	md_el(:ald,[],{:ald=>[["scope", "row"]],:ald_id=>"r"},[])
 ],{},[])
 *** Output of to_html ***
-<table><thead><tr><th>Symbol</th><th>Meaning</th><th>comments</th></tr></thead><tbody><tr><th scope='row' style='text-align: left;'> α</th><td style='text-align: left;'>The first</td><td style='text-align: left;'>I like it.</td>
-</tr><tr><th scope='row' style='text-align: left;'> ℵ</th><td style='text-align: left;'>The first</td><td style='text-align: left;'>I like it.</td>
-</tr></tbody></table>
+<table><thead><tr><th>Symbol</th><th>Meaning</th><th>comments</th></tr></thead><tbody><tr><th scope="row" style="text-align: left;"> α</th><td style="text-align: left;">The first</td><td style="text-align: left;">I like it.</td></tr>
+<tr><th scope="row" style="text-align: left;"> ℵ</th><td style="text-align: left;">The first</td><td style="text-align: left;">I like it.</td></tr>
+</tbody></table>
 *** Output of to_latex ***
 \begin{tabular}{l|l|l}
 Symbol&Meaning&comments\\
 \hline 
- $\alpha${}&The first&I like it.\\
+ $\alpha$&The first&I like it.\\
  &The first&I like it.\\
 \end{tabular}
 *** Output of to_md ***
 SymbolMeaningcomments The firstI like it. The firstI like it.
 *** Output of to_s ***
 SymbolMeaningcomments The firstI like it. The firstI like it.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/misc_sw.md b/spec/block_docs/misc_sw.md
similarity index 63%
rename from tests/unittest/misc_sw.md
rename to spec/block_docs/misc_sw.md
index 71c78b2..09ca193 100644
--- a/tests/unittest/misc_sw.md
+++ b/spec/block_docs/misc_sw.md
@@ -112,13 +112,13 @@ inMenu: true
 md_el(:document,[
 	md_el(:header,["General"],{:level=>3},[]),
 	md_el(:ul,[
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["Operating System"]),
 			" : ",
 			md_link(["Mac OS X"],"switch"),
 			": heaven, after the purgatory of Linux and the hell of Windows."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["Browser"]),
 			": ",
 			md_link(["Firefox"],"firefox"),
@@ -126,7 +126,7 @@ md_el(:document,[
 			md_link(["Camino"],"camino"),
 			"."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["Email"]),
 			": ",
 			md_link(["GMail"],"gmail"),
@@ -138,7 +138,7 @@ md_el(:document,[
 			md_entity("rdquo"),
 			" really works."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["Text Editor"]),
 			": ",
 			md_link(["TextMate"],"textmate"),
@@ -190,7 +190,7 @@ md_el(:document,[
 				md_link(["poignant"],"poignant"),
 				" guide). Python, you say? Python is too academic and snob:"
 			]),
-			md_el(:code,[],{:raw_code=>"$ python       \nPython 2.4.1 (\\#1, Jun  4 2005, 00:54:33) \nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n>>> exit\n'Use Ctrl-D (i.e. EOF) to exit.'\n>>> quit\n'Use Ctrl-D (i.e. EOF) to exit.'"},[])
+			md_el(:code,[],{:raw_code=>"$ python       \nPython 2.4.1 (\\#1, Jun  4 2005, 00:54:33) \nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n>>> exit\n'Use Ctrl-D (i.e. EOF) to exit.'\n>>> quit\n'Use Ctrl-D (i.e. EOF) to exit.'", :lang=>nil},[])
 		],{:want_my_paragraph=>true},[]),
 		md_el(:li,[
 			md_par([
@@ -198,7 +198,7 @@ md_el(:document,[
 				": ",
 				md_link(["JBuilder"],"jbuilder"),
 				" is great software and has a free version (IMHO better than Eclipse). Java is not a pain anymore since it gained ",
-				md_link(["generics"],"javagenerics"),
+				md_link(["generics"],"java-generics"),
 				" and got opensourced."
 			])
 		],{:want_my_paragraph=>false},[]),
@@ -214,32 +214,26 @@ md_el(:document,[
 				"."
 			])
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li,[
-			md_par([
-				md_em(["C++ libraries"]),
-				": * ",
-				md_link(["QT"],"qt"),
-				" for GUIs. * ",
-				md_link(["GSL"],"gsl"),
-				" for math. * ",
-				md_link(["Magick++"],"magick"),
-				" for manipulating images. * ",
-				md_link(["Cairo"],"cairo"),
-				" for creating PDFs. * ",
-				md_link(["Boost"],"boost"),
-				" for just about everything else."
-			])
-		],{:want_my_paragraph=>false},[])
+    md_li([
+       md_par([md_em("C++ libraries"), ":"]),
+       md_el(:ul, [
+         md_el(:li, [md_link("QT", "qt"), " for GUIs."], {:want_my_paragraph=>false}),
+         md_el(:li, [md_link("GSL", "gsl"), " for math."], {:want_my_paragraph=>false}),
+         md_el(:li, [md_link("Magick++", "magick"), " for manipulating images."], {:want_my_paragraph=>false}),
+         md_el(:li, [md_link("Cairo", "cairo"), " for creating PDFs."], {:want_my_paragraph=>false}),
+         md_el(:li, [md_link("Boost", "boost"), " for just about everything else."], {:want_my_paragraph=>false})
+       ])
+    ], false)
 	],{},[]),
 	md_el(:header,["Research"],{:level=>3},[]),
 	md_el(:ul,[
-		md_el(:li_span,[md_em(["Writing papers"]), ": ", md_link(["LaTeX"],"latex")],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[md_em(["Writing papers"]), ": ", md_link(["LaTeX"],"latex")],{:want_my_paragraph=>false},[]),
+		md_el(:li,[
 			md_em(["Writing papers & enjoying the process"]),
 			": ",
 			md_link(["LyX"],"lyx")
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["Handsome figures in your papers"]),
 			": ",
 			md_link(["xfig"],"xfig"),
@@ -247,7 +241,7 @@ md_el(:document,[
 			md_link(["jfig"],"jfig"),
 			"."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["The occasional presentation with many graphical content"]),
 			": ",
 			md_link(["OpenOffice Impress"],"impress"),
@@ -257,13 +251,13 @@ md_el(:document,[
 			md_link(["TexPoint"],"texpoint"),
 			" plugin."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["Managing BibTeX"]),
 			": ",
 			md_link(["jabref"],"jabref"),
 			": multi-platform, for all your bibtex needs."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["IEEExplore and BibTeX"]),
 			": convert citations using ",
 			md_link(["BibConverter"],"bibconverter"),
@@ -272,12 +266,12 @@ md_el(:document,[
 	],{},[]),
 	md_el(:header,["Cool websites"],{:level=>3},[]),
 	md_el(:ul,[
-		md_el(:li_span,[
+		md_el(:li,[
 			md_em(["Best site in the wwworld"]),
 			": ",
 			md_link(["Wikipedia"],"wikipedia")
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			md_link(["Mutopia"],"mutopia"),
 			" for sheet music; ",
 			md_link(["the Gutenberg Project"],"gutenberg"),
@@ -285,8 +279,8 @@ md_el(:document,[
 			md_link(["LiberLiber"],"liberliber"),
 			" for books in italian."
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[md_em(["Blogs"]), ": ", md_link(["Bloglines"],"bloglines")],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[md_em(["Blogs"]), ": ", md_link(["Bloglines"],"bloglines")],{:want_my_paragraph=>false},[]),
+		md_el(:li,[
 			md_em(["Sharing photos"]),
 			": ",
 			md_link(["flickr"],"flickr"),
@@ -330,87 +324,99 @@ md_el(:document,[
 	md_ref_def("mutopia", "http://www.mutopiaproject.org/", {:title=>nil}),
 	md_ref_def("liberliber", "http://www.liberliber.it/", {:title=>nil}),
 	md_ref_def("gutenberg", "http://www.gutenberg.org/", {:title=>nil}),
-	md_ref_def("javagenerics", "http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html", {:title=>nil})
+	md_ref_def("java-generics", "http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html", {:title=>nil})
 ],{},[])
 *** Output of to_html ***
-<h3 id='general'>General</h3>
+<h3 id="general">General</h3>
 
 <ul>
-<li><em>Operating System</em> : <a href='http://www.apple.com/getamac/'>Mac OS X</a>: heaven, after the purgatory of Linux and the hell of Windows.</li>
+<li><em>Operating System</em> : <a href="http://www.apple.com/getamac/">Mac OS X</a>: heaven, after the purgatory of Linux and the hell of Windows.</li>
 
-<li><em>Browser</em>: <a href='http://getfirefox.com/'>Firefox</a>. On a Mac, <a href='http://www.caminobrowser.org/'>Camino</a>.</li>
+<li><em>Browser</em>: <a href="http://getfirefox.com/">Firefox</a>. On a Mac, <a href="http://www.caminobrowser.org/">Camino</a>.</li>
 
-<li><em>Email</em>: <a href='http://gmail.com/'>GMail</a>, “search, don’t sort” really works.</li>
+<li><em>Email</em>: <a href="http://gmail.com/">GMail</a>, “search, don’t sort” really works.</li>
 
-<li><em>Text Editor</em>: <a href='http://www.apple.com/getamac/'>TextMate</a>, you have to buy it, but it’s worth every penny. There are rumours that it’s been converting (recovering) Emacs users (addicts). Unfortunately, it’s Mac only. An alternative is <a href='http://www.jedit.org/'>jedit</a> (GPL, Java).</li>
+<li><em>Text Editor</em>: <a href="http://www.apple.com/getamac/">TextMate</a>, you have to buy it, but it’s worth every penny. There are rumours that it’s been converting (recovering) Emacs users (addicts). Unfortunately, it’s Mac only. An alternative is <a href="http://www.jedit.org/">jedit</a> (GPL, Java).</li>
 </ul>
 
-<h3 id='development'>Development</h3>
+<h3 id="development">Development</h3>
 
 <ul>
 <li>
-<p><em>Build system</em>: <a href='http://www.cmake.org/'>cmake</a>, throw the <a href='http://sources.redhat.com/autobook/'>autotools</a> away.</p>
+<p><em>Build system</em>: <a href="http://www.cmake.org/">cmake</a>, throw the <a href="http://sources.redhat.com/autobook/">autotools</a> away.</p>
 </li>
 
 <li>
-<p><em>Source code control system</em>: ditch CVS for <a href='http://subversion.tigris.org'>subversion</a>.</p>
+<p><em>Source code control system</em>: ditch CVS for <a href="http://subversion.tigris.org">subversion</a>.</p>
 </li>
 
 <li>
-<p><em>Project management</em>: <a href='http://trac.edgewall.org/'>Trac</a> tracks everything.</p>
+<p><em>Project management</em>: <a href="http://trac.edgewall.org/">Trac</a> tracks everything.</p>
 </li>
 
 <li>
-<p><em>Scripting language</em>: <a href='http://www.ruby-lang.org/'>Ruby</a> is Japanese pragmatism (and has a <a href='http://poignantguide.net/ruby/'>poignant</a> guide). Python, you say? Python is too academic and snob:</p>
+<p><em>Scripting language</em>: <a href="http://www.ruby-lang.org/">Ruby</a> is Japanese pragmatism (and has a <a href="http://poignantguide.net/ruby/">poignant</a> guide). Python, you say? Python is too academic and snob:</p>
 
 <pre><code>$ python       
 Python 2.4.1 (\#1, Jun  4 2005, 00:54:33) 
-Type "help", "copyright", "credits" or "license" for more information.
+Type "help", "copyright", "credits" or "license" for more information.
 >>> exit
-'Use Ctrl-D (i.e. EOF) to exit.'
+'Use Ctrl-D (i.e. EOF) to exit.'
 >>> quit
-'Use Ctrl-D (i.e. EOF) to exit.'</code></pre>
+'Use Ctrl-D (i.e. EOF) to exit.'</code></pre>
 </li>
 
 <li>
-<p><em>Java IDE</em>: <a href='http://www.borland.com/us/products/jbuilder/index.html'>JBuilder</a> is great software and has a free version (IMHO better than Eclipse). Java is not a pain anymore since it gained <a href='http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html'>generics</a> and got opensourced.</p>
+<p><em>Java IDE</em>: <a href="http://www.borland.com/us/products/jbuilder/index.html">JBuilder</a> is great software and has a free version (IMHO better than Eclipse). Java is not a pain anymore since it gained <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html">generics</a> and got opensourced.</p>
 </li>
 
 <li>
-<p><em>Mark-up language</em>: HTML is so 2001, why don’t you take at look at <a href='http://en.wikipedia.org/wiki/Markdown'>Markdown</a>? <a href='data/misc_markdown.png'>Look at the source of this page</a>.</p>
+<p><em>Mark-up language</em>: HTML is so 2001, why don’t you take at look at <a href="http://en.wikipedia.org/wiki/Markdown">Markdown</a>? <a href="data/misc_markdown.png">Look at the source of this page</a>.</p>
 </li>
 
 <li>
-<p><em>C++ libraries</em>: * <a href='http://www.trolltech.no/'>QT</a> for GUIs. * <a href='http://www.gnu.org/software/gsl/'>GSL</a> for math. * <a href='http://www.imagemagick.org/Magick++/'>Magick++</a> for manipulating images. * <a href='http://cairographics.org/'>Cairo</a> for creating PDFs. * <a href='http://www.boost.org/'>Boost</a> for just about everything else.</p>
+<p><em>C++ libraries</em>:</p>
+
+<ul>
+<li><a href="http://www.trolltech.no/">QT</a> for GUIs.</li>
+
+<li><a href="http://www.gnu.org/software/gsl/">GSL</a> for math.</li>
+
+<li><a href="http://www.imagemagick.org/Magick++/">Magick++</a> for manipulating images.</li>
+
+<li><a href="http://cairographics.org/">Cairo</a> for creating PDFs.</li>
+
+<li><a href="http://www.boost.org/">Boost</a> for just about everything else.</li>
+</ul>
 </li>
 </ul>
 
-<h3 id='research'>Research</h3>
+<h3 id="research">Research</h3>
 
 <ul>
-<li><em>Writing papers</em>: <a href='http://en.wikipedia.org/wiki/LaTeX'>LaTeX</a></li>
+<li><em>Writing papers</em>: <a href="http://en.wikipedia.org/wiki/LaTeX">LaTeX</a></li>
 
-<li><em>Writing papers & enjoying the process</em>: <a href='http://www.lyx.org'>LyX</a></li>
+<li><em>Writing papers & enjoying the process</em>: <a href="http://www.lyx.org">LyX</a></li>
 
-<li><em>Handsome figures in your papers</em>: <a href='http://www.xfig.org/'>xfig</a> or, better, <a href='http://tams-www.informatik.uni-hamburg.de/applets/jfig/'>jfig</a>.</li>
+<li><em>Handsome figures in your papers</em>: <a href="http://www.xfig.org/">xfig</a> or, better, <a href="http://tams-www.informatik.uni-hamburg.de/applets/jfig/">jfig</a>.</li>
 
-<li><em>The occasional presentation with many graphical content</em>: <a href='http://www.openoffice.org/product/impress.html'>OpenOffice Impress</a> (using the <a href='http://ooolatex.sourceforge.net/'>OOOlatex plugin</a>); the alternative is PowerPoint with the <a href='http://texpoint.necula.org/'>TexPoint</a> plugin.</li>
+<li><em>The occasional presentation with many graphical content</em>: <a href="http://www.openoffice.org/product/impress.html">OpenOffice Impress</a> (using the <a href="http://ooolatex.sourceforge.net/">OOOlatex plugin</a>); the alternative is PowerPoint with the <a href="http://texpoint.necula.org/">TexPoint</a> plugin.</li>
 
-<li><em>Managing BibTeX</em>: <a href='http://jabref.sourceforge.net/'>jabref</a>: multi-platform, for all your bibtex needs.</li>
+<li><em>Managing BibTeX</em>: <a href="http://jabref.sourceforge.net/">jabref</a>: multi-platform, for all your bibtex needs.</li>
 
-<li><em>IEEExplore and BibTeX</em>: convert citations using <a href='http://www.bibconverter.net/ieeexplore/'>BibConverter</a>.</li>
+<li><em>IEEExplore and BibTeX</em>: convert citations using <a href="http://www.bibconverter.net/ieeexplore/">BibConverter</a>.</li>
 </ul>
 
-<h3 id='cool_websites'>Cool websites</h3>
+<h3 id="cool_websites">Cool websites</h3>
 
 <ul>
-<li><em>Best site in the wwworld</em>: <a href='http://en.wikipedia.org/'>Wikipedia</a></li>
+<li><em>Best site in the wwworld</em>: <a href="http://en.wikipedia.org/">Wikipedia</a></li>
 
-<li><a href='http://www.mutopiaproject.org/'>Mutopia</a> for sheet music; <a href='http://www.gutenberg.org/'>the Gutenberg Project</a> for books; <a href='http://www.liberliber.it/'>LiberLiber</a> for books in italian.</li>
+<li><a href="http://www.mutopiaproject.org/">Mutopia</a> for sheet music; <a href="http://www.gutenberg.org/">the Gutenberg Project</a> for books; <a href="http://www.liberliber.it/">LiberLiber</a> for books in italian.</li>
 
-<li><em>Blogs</em>: <a href='http://bloglines.com/'>Bloglines</a></li>
+<li><em>Blogs</em>: <a href="http://bloglines.com/">Bloglines</a></li>
 
-<li><em>Sharing photos</em>: <a href='http://www.flickr.com/'>flickr</a> exposes an API you can use.</li>
+<li><em>Sharing photos</em>: <a href="http://www.flickr.com/">flickr</a> exposes an API you can use.</li>
 </ul>
 *** Output of to_latex ***
 \hypertarget{general}{}\subsubsection*{{General}}\label{general}
@@ -418,8 +424,8 @@ Type "help", "copyright", "credits" or "licen
 \begin{itemize}%
 \item \emph{Operating System} : \href{http://www.apple.com/getamac/}{Mac OS X}: heaven, after the purgatory of Linux and the hell of Windows.
 \item \emph{Browser}: \href{http://getfirefox.com/}{Firefox}. On a Mac, \href{http://www.caminobrowser.org/}{Camino}.
-\item \emph{Email}: \href{http://gmail.com/}{GMail}, ``{}search, don'{}t sort''{} really works.
-\item \emph{Text Editor}: \href{http://www.apple.com/getamac/}{TextMate}, you have to buy it, but it'{}s worth every penny. There are rumours that it'{}s been converting (recovering) Emacs users (addicts). Unfortunately, it'{}s Mac only. An alternative is \href{http://www.jedit.org/}{jedit} (GPL, Java).
+\item \emph{Email}: \href{http://gmail.com/}{GMail}, ``search, don't sort'' really works.
+\item \emph{Text Editor}: \href{http://www.apple.com/getamac/}{TextMate}, you have to buy it, but it's worth every penny. There are rumours that it's been converting (recovering) Emacs users (addicts). Unfortunately, it's Mac only. An alternative is \href{http://www.jedit.org/}{jedit} (GPL, Java).
 
 \end{itemize}
 \hypertarget{development}{}\subsubsection*{{Development}}\label{development}
@@ -447,11 +453,19 @@ Type "help", "copyright", "credits" or "license" for more information.
 \item \emph{Java IDE}: \href{http://www.borland.com/us/products/jbuilder/index.html}{JBuilder} is great software and has a free version (IMHO better than Eclipse). Java is not a pain anymore since it gained \href{http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html}{generics} and got opensourced.
 
 
-\item \emph{Mark-up language}: HTML is so 2001, why don'{}t you take at look at \href{http://en.wikipedia.org/wiki/Markdown}{Markdown}? \href{data/misc_markdown.png}{Look at the source of this page}.
+\item \emph{Mark-up language}: HTML is so 2001, why don't you take at look at \href{http://en.wikipedia.org/wiki/Markdown}{Markdown}? \href{data/misc_markdown.png}{Look at the source of this page}.
+
 
+\item \emph{C++ libraries}:
 
-\item \emph{C++ libraries}: * \href{http://www.trolltech.no/}{QT} for GUIs. * \href{http://www.gnu.org/software/gsl/}{GSL} for math. * \href{http://www.imagemagick.org/Magick++/}{Magick++} for manipulating images. * \href{http://cairographics.org/}{Cairo} for creating PDFs. * \href{http://www.boost.org/}{Boost} for just about everything else.
+\begin{itemize}%
+\item \href{http://www.trolltech.no/}{QT} for GUIs.
+\item \href{http://www.gnu.org/software/gsl/}{GSL} for math.
+\item \href{http://www.imagemagick.org/Magick++/}{Magick++} for manipulating images.
+\item \href{http://cairographics.org/}{Cairo} for creating PDFs.
+\item \href{http://www.boost.org/}{Boost} for just about everything else.
 
+\end{itemize}
 
 
 \end{itemize}
@@ -476,62 +490,111 @@ Type "help", "copyright", "credits" or "license" for more information.
 
 \end{itemize}
 *** Output of to_md ***
-General-perating System: Mac OS X: heaven,
-after the purgatory of Linux and
-the hell of Windows.
--rowser: Firefox. On a Mac, Camino.
--mail: GMail, search, don t sort
-really works.
--ext Editor: TextMate, you have to
-buy it, but it s worth every penny.
-There are rumours that it s been
-converting (recovering) Emacs users
-(addicts). Unfortunately, it s Mac
-only. An alternative is jedit(GPL,
-Java).
-
-Development-Build system: cmake, throw the autotools away.
--Source code control system: ditch CVS for subversion.
--Project management: Trac tracks everything.
--Scripting language: Ruby is Japanese pragmatism (and has a poignant guide). Python, you say? Python is too academic and snob:
--Java IDE: JBuilder is great software and has a free version (IMHO better than Eclipse). Java is not a pain anymore since it gained generics and got opensourced.
--Mark-up language: HTML is so 2001, why dont you take at look at Markdown? Look at the source of this page.
--C++ libraries: * QT for GUIs. * GSL for math. * Magick++ for manipulating images. * Cairo for creating PDFs. * Boost for just about everything else.
-
-Research-riting papers: LaTeX
--Writing papers & enjoying the process
-: LyX
--andsome figures in your papers:
-xfigor, better, jfig.
--The occasional presentation with many graphical content
-: OpenOffice Impress(using the
-OOOlatex plugin); the alternative
-is PowerPoint with the TexPoint
-plugin.
--anaging BibTeX: jabref:
-multi-platform, for all your bibtex
-needs.
--EEExplore and BibTeX: convert
-citations using BibConverter.
-
-Cool websites-est site in the wwworld: Wikipedia
--utopiafor sheet music;
-the Gutenberg Projectfor books;
-LiberLiberfor books in italian.
--logs: Bloglines
--haring photos: flickrexposes an
-API you can use.
-*** Output of to_s ***
-GeneralOperating System : Mac OS X: heaven, after the purgatory of Linux and the hell of Windows.Browser: Firefox. On a Mac, Camino.Email: GMail, search, dont sort really works.Text Editor: TextMate, you have to buy it, but its worth every penny. There are rumours that its been converting (recovering) Emacs users (addicts). Unfortunately, its Mac only. An alternative is jedit (GPL, Java).DevelopmentBuild system: cmake, throw the autotools away.Source code control system: ditch CVS for su [...]
-*** EOF ***
+Subject: Software not painful to use
+Subject_short: painless software
+Topic: /misc/coolsw
+Archive: no
+Date: Nov 20 2006
+Order: -9.5
+inMenu: true
 
 
+### General
 
-	OK!
+* *Operating System* : [Mac OS X][switch]: heaven, after the purgatory of Linux
+  and the hell of Windows.
+* *Browser*: [Firefox][firefox]. On a Mac, [Camino][camino].
+* *Email*: [GMail][gmail], "search, don't sort" really works.
+* *Text Editor*: [TextMate][textmate], you have to buy it, but it's worth every
+  penny. There are rumours that it's been converting (recovering) Emacs
+  users (addicts). Unfortunately, it's Mac only. An alternative is
+  [jedit][jedit] (GPL, Java).
+
+### Development
 
+* *Build system*: [cmake][cmake], throw the [autotools][autotools] away.
+* *Source code control system*: ditch CVS for [subversion][subversion].
+* *Project management*: [Trac][trac] tracks everything.
+* *Scripting language*: [Ruby][ruby] is Japanese pragmatism (and has a [poignant][poignant] guide).
+   Python, you say? Python is too academic and snob:
 
+      $ python
+      Python 2.4.1 (\#1, Jun  4 2005, 00:54:33)
+      Type "help", "copyright", "credits" or "license" for more information.
+      >>> exit
+      'Use Ctrl-D (i.e. EOF) to exit.'
+      >>> quit
+      'Use Ctrl-D (i.e. EOF) to exit.'
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+* *Java IDE*: [JBuilder][jbuilder] is great software and has a free version (IMHO better than Eclipse). Java
+ is not a pain anymore since it gained [generics][java-generics] and got opensourced.
+* *Mark-up language*: HTML is so 2001, why don't you take at look at [Markdown][markdown]? [Look at the source of this page](data/misc_markdown.png).
+* *C++ libraries*:
+    * [QT][qt] for GUIs.
+    * [GSL][gsl] for math.
+    * [Magick++][magick] for manipulating images.
+    * [Cairo][cairo] for creating PDFs.
+    * [Boost][boost] for just about everything else.
+
+
+### Research
+
+* *Writing papers*: [LaTeX][latex]
+* *Writing papers & enjoying the process*: [LyX][lyx]
+* *Handsome figures in your papers*: [xfig][xfig] or, better, [jfig][jfig].
+* *The occasional presentation with many graphical content*:
+  [OpenOffice Impress][impress] (using the [OOOlatex plugin][ooolatex]);
+  the alternative is PowerPoint with the [TexPoint][texpoint] plugin.
+* *Managing BibTeX*: [jabref][jabref]: multi-platform, for all your bibtex needs.
+* *IEEExplore and BibTeX*: convert citations using [BibConverter][bibconverter].
+
+### Cool websites
+
+* *Best site in the wwworld*: [Wikipedia][wikipedia]
+* [Mutopia][mutopia] for sheet music; [the Gutenberg Project][gutenberg] for books; [LiberLiber][liberliber] for books in italian.
+* *Blogs*: [Bloglines][bloglines]
+* *Sharing photos*: [flickr][flickr] exposes an API you can use.
+
+
+[firefox]:   http://getfirefox.com/
+[gmail]:     http://gmail.com/
+[bloglines]: http://bloglines.com/
+[wikipedia]: http://en.wikipedia.org/
+[ruby]:      http://www.ruby-lang.org/
+[poignant]:  http://poignantguide.net/ruby/
+[webgen]:    http://webgen.rubyforge.org/
+[markdown]:  http://daringfireball.net/projects/markdown/
+[latex]:     http://en.wikipedia.org/wiki/LaTeX
+[lyx]:       http://www.lyx.org
+[impress]:   http://www.openoffice.org/product/impress.html
+[ooolatex]:  http://ooolatex.sourceforge.net/
+[texpoint]:  http://texpoint.necula.org/
+[jabref]:    http://jabref.sourceforge.net/
+[camino]:    http://www.caminobrowser.org/
+[switch]:    http://www.apple.com/getamac/
+[textmate]:  http://www.apple.com/getamac/
+[cmake]:     http://www.cmake.org/
+[xfig]:      http://www.xfig.org/
+[jfig]:         http://tams-www.informatik.uni-hamburg.de/applets/jfig/
+[subversion]:   http://subversion.tigris.org
+[jbuilder]:     http://www.borland.com/us/products/jbuilder/index.html
+[flickr]:       http://www.flickr.com/
+[myflickr]:     http://www.flickr.com/photos/censi
+[bibconverter]: http://www.bibconverter.net/ieeexplore/
+[autotools]:    http://sources.redhat.com/autobook/
+[jedit]:        http://www.jedit.org/
+[qt]:           http://www.trolltech.no/
+[gsl]:          http://www.gnu.org/software/gsl/
+[magick]:       http://www.imagemagick.org/Magick++/
+[cairo]:        http://cairographics.org/
+[boost]:        http://www.boost.org/
+[markdown]:     http://en.wikipedia.org/wiki/Markdown
+[trac]:         http://trac.edgewall.org/
+[mutopia]:      http://www.mutopiaproject.org/
+[liberliber]:   http://www.liberliber.it/
+[gutenberg]:    http://www.gutenberg.org/
+[java-generics]: http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html
+
+
+*** Output of to_s ***
+GeneralOperating System : Mac OS X: heaven, after the purgatory of Linux and the hell of Windows.Browser: Firefox. On a Mac, Camino.Email: GMail, search, dont sort really works.Text Editor: TextMate, you have to buy it, but its worth every penny. There are rumours that its been converting (recovering) Emacs users (addicts). Unfortunately, its Mac only. An alternative is jedit (GPL, Java).DevelopmentBuild system: cmake, throw the autotools away.Source code control system: ditch CVS for su [...]
diff --git a/tests/unittest/olist.md b/spec/block_docs/olist.md
similarity index 60%
rename from tests/unittest/olist.md
rename to spec/block_docs/olist.md
index 9d9bb4a..89aeeb3 100644
--- a/tests/unittest/olist.md
+++ b/spec/block_docs/olist.md
@@ -11,9 +11,9 @@ This is a list:
 md_el(:document,[
 	md_par(["This is a list:"]),
 	md_el(:ol,[
-		md_el(:li_span,["one"],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,["two"],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,["three"],{:want_my_paragraph=>false},[])
+		md_el(:li,["one"],{:want_my_paragraph=>false},[]),
+		md_el(:li,["two"],{:want_my_paragraph=>false},[]),
+		md_el(:li,["three"],{:want_my_paragraph=>false},[])
 	],{},[])
 ],{},[])
 *** Output of to_html ***
@@ -38,20 +38,8 @@ This is a list:
 *** Output of to_md ***
 This is a list:
 
-1.  one
-2.  two
-3.  three
+1. one
+2. two
+3. three
 *** Output of to_s ***
 This is a list:onetwothree
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/one.md b/spec/block_docs/one.md
similarity index 70%
rename from tests/unittest/one.md
rename to spec/block_docs/one.md
index 6618f96..a5ef0d6 100644
--- a/tests/unittest/one.md
+++ b/spec/block_docs/one.md
@@ -13,15 +13,3 @@ One line
 One line
 *** Output of to_s ***
 One line
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/paragraph.md b/spec/block_docs/paragraph.md
similarity index 71%
rename from tests/unittest/paragraph.md
rename to spec/block_docs/paragraph.md
index d2960ec..9dd04bf 100644
--- a/tests/unittest/paragraph.md
+++ b/spec/block_docs/paragraph.md
@@ -14,15 +14,3 @@ Paragraph
 Paragraph
 *** Output of to_s ***
 Paragraph
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/paragraph_rules/dont_merge_ref.md b/spec/block_docs/paragraph_rules/dont_merge_ref.md
similarity index 84%
rename from tests/unittest/paragraph_rules/dont_merge_ref.md
rename to spec/block_docs/paragraph_rules/dont_merge_ref.md
index f5d26af..2a34996 100644
--- a/tests/unittest/paragraph_rules/dont_merge_ref.md
+++ b/spec/block_docs/paragraph_rules/dont_merge_ref.md
@@ -34,21 +34,13 @@ Paragraph
 Paragraph
 *** Output of to_md ***
 Paragraph
+[google1]: #
 
 Paragraph
+ [google2]: #
 
 Paragraph
+  [google3]: #
+
 *** Output of to_s ***
 ParagraphParagraphParagraph
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/paragraph_rules/tab_is_blank.md b/spec/block_docs/paragraph_rules/tab_is_blank.md
similarity index 77%
rename from tests/unittest/paragraph_rules/tab_is_blank.md
rename to spec/block_docs/paragraph_rules/tab_is_blank.md
index 1527380..6ef932b 100644
--- a/tests/unittest/paragraph_rules/tab_is_blank.md
+++ b/spec/block_docs/paragraph_rules/tab_is_blank.md
@@ -22,15 +22,3 @@ Paragraph1
 Paragraph2
 *** Output of to_s ***
 Paragraph1Paragraph2
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/paragraphs.md b/spec/block_docs/paragraphs.md
similarity index 79%
rename from tests/unittest/paragraphs.md
rename to spec/block_docs/paragraphs.md
index 9e08b41..2102b5d 100644
--- a/tests/unittest/paragraphs.md
+++ b/spec/block_docs/paragraphs.md
@@ -34,7 +34,7 @@ Paragraph 1
 
 Paragraph 2
 
-Paragraph 3 Paragraph 4 Paragraph Br-{\tt \char62}\newline Paragraph 5
+Paragraph 3 Paragraph 4 Paragraph Br-{\tt \symbol{62}}\newline Paragraph 5
 *** Output of to_md ***
 Paragraph 1
 
@@ -44,15 +44,3 @@ Paragraph 3 Paragraph 4 Paragraph Br->
 Paragraph 5
 *** Output of to_s ***
 Paragraph 1Paragraph 2Paragraph 3 Paragraph 4 Paragraph Br->Paragraph 5
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/recover/recover_links.md b/spec/block_docs/recover/recover_links.md
similarity index 55%
rename from tests/unittest/recover/recover_links.md
rename to spec/block_docs/recover/recover_links.md
index 530309f..eea9c32 100644
--- a/tests/unittest/recover/recover_links.md
+++ b/spec/block_docs/recover/recover_links.md
@@ -1,27 +1,15 @@
-This shows how Maruku recovers from parsing errors
+Maruku should not mangle references that don't exist.
 *** Parameters: ***
 {:on_error=>:warning}
 *** Markdown input: ***
 Search on [Google images][ 	GoOgle search ]
 *** Output of inspect ***
-md_el(:document,[md_par(["Search on ", md_link(["Google images"],"google_search")])],{},[])
+md_el(:document,[md_par(["Search on ", md_link(["Google images"]," \tGoOgle search ")])],{},[])
 *** Output of to_html ***
-<p>Search on <span>Google images</span></p>
+<p>Search on [Google images][ 	GoOgle search ]</p>
 *** Output of to_latex ***
 Search on Google images
 *** Output of to_md ***
-Search on Google images
+Search on [Google images][ 	GoOgle search ]
 *** Output of to_s ***
 Search on Google images
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/pending/ref.md b/spec/block_docs/ref_with_period.md
similarity index 52%
rename from tests/unittest/pending/ref.md
rename to spec/block_docs/ref_with_period.md
index a3c6452..4d95518 100644
--- a/tests/unittest/pending/ref.md
+++ b/spec/block_docs/ref_with_period.md
@@ -8,26 +8,17 @@ Write a comment here
 
 *** Output of inspect ***
 md_el(:document,[
-	md_par([md_link(["a. b"],"a_b"), " is a link."]),
-	md_ref_def("a_b", "http://site.com/", {:title=>nil})
+	md_par([md_link(["a. b"],nil), " is a link."]),
+	md_ref_def("a. b", "http://site.com/", {:title=>nil})
 ],{},[])
 *** Output of to_html ***
-<p><a href='http://site.com/'>a. b</a> is a link.</p>
+<p><a href="http://site.com/">a. b</a> is a link.</p>
 *** Output of to_latex ***
 \href{http://site.com/}{a. b} is a link.
 *** Output of to_md ***
-a. bis a link.
-*** Output of to_s ***
-a. b is a link.
-*** EOF ***
-
-
-
-	OK!
-
+[a. b] is a link.
 
+[a. b]: http://site.com/
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+*** Output of to_s ***
+a. b is a link.
diff --git a/spec/block_docs/ref_with_title.md b/spec/block_docs/ref_with_title.md
new file mode 100644
index 0000000..45569b1
--- /dev/null
+++ b/spec/block_docs/ref_with_title.md
@@ -0,0 +1,22 @@
+Comment
+*** Parameters: ***
+{}
+*** Markdown input: ***
+[bar][1].
+
+[1]: /url/ "Title"
+*** Output of inspect ***
+md_el(:document,[
+        md_par([md_link(["bar"],"1"), "."]),
+        md_ref_def("1", "/url/", {:title=>"Title"})
+],{},[])
+*** Output of to_html ***
+<p><a href="/url/" title="Title">bar</a>.</p>
+*** Output of to_latex ***
+\href{/url/}{bar}.
+*** Output of to_md ***
+[bar][1].
+
+[1]: /url/ "Title"
+*** Output of to_s ***
+bar.
diff --git a/tests/unittest/references/long_example.md b/spec/block_docs/references/long_example.md
similarity index 54%
rename from tests/unittest/references/long_example.md
rename to spec/block_docs/references/long_example.md
index a080cd7..8506e94 100644
--- a/tests/unittest/references/long_example.md
+++ b/spec/block_docs/references/long_example.md
@@ -51,33 +51,26 @@ md_el(:document,[
 	])
 ],{},[])
 *** Output of to_html ***
-<p>filters – including <a href='http://docutils.sourceforge.net/mirror/setext.html'>Setext</a>, <a href='http://www.aaronsw.com/2002/atx/'>atx</a>, <a href='http://textism.com/tools/textile/'>Textile</a>, <a href='http://docutils.sourceforge.net/rst.html'>reStructuredText</a>, <a href='http://www.triptico.com/software/grutatxt.html'>Grutatext</a>, and <a href='http://ettext.taint.org/doc/'>EtText</a> – the single biggest source of inspiration for Markdown’s syntax is th [...]
+<p>filters – including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>, <a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> – the single biggest source of inspiration for Markdown’s syntax is the format of plain  [...]
 
-<p>To this end, Markdown’s syntax is comprised entirely of punctuation</p>
+<p>To this end, Markdown’s syntax is comprised entirely of punctuation</p>
 *** Output of to_latex ***
-filters --{} including \href{http://docutils.sourceforge.net/mirror/setext.html}{Setext}, \href{http://www.aaronsw.com/2002/atx/}{atx}, \href{http://textism.com/tools/textile/}{Textile}, \href{http://docutils.sourceforge.net/rst.html}{reStructuredText}, \href{http://www.triptico.com/software/grutatxt.html}{Grutatext}, and \href{http://ettext.taint.org/doc/}{EtText} --{} the single biggest source of inspiration for Markdown'{}s syntax is the format of plain text email.
+filters -- including \href{http://docutils.sourceforge.net/mirror/setext.html}{Setext}, \href{http://www.aaronsw.com/2002/atx/}{atx}, \href{http://textism.com/tools/textile/}{Textile}, \href{http://docutils.sourceforge.net/rst.html}{reStructuredText}, \href{http://www.triptico.com/software/grutatxt.html}{Grutatext}, and \href{http://ettext.taint.org/doc/}{EtText} -- the single biggest source of inspiration for Markdown's syntax is the format of plain text email.
 
-To this end, Markdown'{}s syntax is comprised entirely of punctuation
+To this end, Markdown's syntax is comprised entirely of punctuation
 *** Output of to_md ***
-filters including Setext, atx, Textile,
-reStructuredText, Grutatext, and EtText
-the single biggest source of
-inspiration for Markdown s syntax is
-the format of plain text email.
-
-To this end, Markdown s syntax is
-comprised entirely of punctuation
-*** Output of to_s ***
-filters  including Setext, atx, Textile, reStructuredText, Grutatext, and EtText  the single biggest source of inspiration for Markdowns syntax is the format of plain text email.To this end, Markdowns syntax is comprised entirely of punctuation
-*** EOF ***
-
-
-
-	OK!
 
+filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4],
+[Grutatext] [5], and [EtText] [6] -- the single biggest source of
+inspiration for Markdown's syntax is the format of plain text email.
 
+  [1]: http://docutils.sourceforge.net/mirror/setext.html
+  [2]: http://www.aaronsw.com/2002/atx/
+  [3]: http://textism.com/tools/textile/
+  [4]: http://docutils.sourceforge.net/rst.html
+  [5]: http://www.triptico.com/software/grutatxt.html
+  [6]: http://ettext.taint.org/doc/
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+To this end, Markdown's syntax is comprised entirely of punctuation
+*** Output of to_s ***
+filters  including Setext, atx, Textile, reStructuredText, Grutatext, and EtText  the single biggest source of inspiration for Markdowns syntax is the format of plain text email.To this end, Markdowns syntax is comprised entirely of punctuation
diff --git a/tests/unittest/references/spaces_and_numbers.md b/spec/block_docs/references/spaces_and_numbers.md
similarity index 72%
rename from tests/unittest/references/spaces_and_numbers.md
rename to spec/block_docs/references/spaces_and_numbers.md
index 46a9736..d83a593 100644
--- a/tests/unittest/references/spaces_and_numbers.md
+++ b/spec/block_docs/references/spaces_and_numbers.md
@@ -13,15 +13,3 @@ md_el(:document,[md_ref_def("6", "http://ettext.taint.org/doc/", {:title=>nil})]
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/smartypants.md b/spec/block_docs/smartypants.md
similarity index 66%
rename from tests/unittest/smartypants.md
rename to spec/block_docs/smartypants.md
index f9e74ec..83b3b86 100644
--- a/tests/unittest/smartypants.md
+++ b/spec/block_docs/smartypants.md
@@ -19,7 +19,7 @@ I -- too -- met << some curly quotes >> there or <<here>>No space.
 
 *** Output of inspect ***
 md_el(:document,[
-	md_el(:code,[],{:raw_code=>"'Twas a \"test\" to 'remember' in the '90s."},[]),
+	md_el(:code,[],{:raw_code=>"'Twas a \"test\" to 'remember' in the '90s.", :lang=>nil},[]),
 	md_par([
 		md_entity("lsquo"),
 		"Twas a ",
@@ -34,7 +34,7 @@ md_el(:document,[
 		md_entity("rsquo"),
 		"90s."
 	]),
-	md_el(:code,[],{:raw_code=>"It was --- in a sense --- really... interesting."},[]),
+	md_el(:code,[],{:raw_code=>"It was --- in a sense --- really... interesting.", :lang=>nil},[]),
 	md_par([
 		"It was ",
 		md_entity("mdash"),
@@ -44,7 +44,7 @@ md_el(:document,[
 		md_entity("hellip"),
 		" interesting."
 	]),
-	md_el(:code,[],{:raw_code=>"I -- too -- met << some curly quotes >> there or <<here>>No space."},[]),
+	md_el(:code,[],{:raw_code=>"I -- too -- met << some curly quotes >> there or <<here>>No space.", :lang=>nil},[]),
 	md_par([
 		"I ",
 		md_entity("ndash"),
@@ -62,65 +62,58 @@ md_el(:document,[
 		md_entity("raquo"),
 		"No space."
 	]),
-	md_el(:code,[],{:raw_code=>"She was 6\\\"12\\'."},[]),
+	md_el(:code,[],{:raw_code=>"She was 6\\\"12\\'.", :lang=>nil},[]),
 	md_el(:quote,[
 		md_par(["She was 6", md_entity("quot"), "12", md_entity("apos"), "."])
 	],{},[])
 ],{},[])
 *** Output of to_html ***
-<pre><code>'Twas a "test" to 'remember' in the '90s.</code></pre>
+<pre><code>'Twas a "test" to 'remember' in the '90s.</code></pre>
 
-<p>‘Twas a “test” to ‘remember’ in the ’90s.</p>
+<p>‘Twas a “test” to ‘remember’ in the ’90s.</p>
 
 <pre><code>It was --- in a sense --- really... interesting.</code></pre>
 
-<p>It was — in a sense — really… interesting.</p>
+<p>It was — in a sense — really… interesting.</p>
 
 <pre><code>I -- too -- met << some curly quotes >> there or <<here>>No space.</code></pre>
 
-<p>I – too – met « some curly quotes » there or «here»No space.</p>
+<p>I – too – met « some curly quotes » there or «here»No space.</p>
 
-<pre><code>She was 6\"12\'.</code></pre>
+<pre><code>She was 6\"12\'.</code></pre>
 
 <blockquote>
-<p>She was 6"12'.</p>
+<p>She was 6"12'.</p>
 </blockquote>
 *** Output of to_latex ***
 \begin{verbatim}'Twas a "test" to 'remember' in the '90s.\end{verbatim}
-`{}Twas a ``{}test''{} to `{}remember'{} in the '{}90s.
+`Twas a ``test'' to `remember' in the '90s.
 
 \begin{verbatim}It was --- in a sense --- really... interesting.\end{verbatim}
-It was ---{} in a sense ---{} really\ldots{} interesting.
+It was --- in a sense --- really\ldots{} interesting.
 
 \begin{verbatim}I -- too -- met << some curly quotes >> there or <<here>>No space.\end{verbatim}
-I --{} too --{} met \guillemotleft{}~{}some curly quotes~{}\guillemotright{} there or \guillemotleft{}here\guillemotright{}No space.
+I -- too -- met \guillemotleft{}~some curly quotes~\guillemotright{} there or \guillemotleft{}here\guillemotright{}No space.
 
 \begin{verbatim}She was 6\"12\'.\end{verbatim}
 \begin{quote}%
-She was 6"{}12'{}.
+She was 6"12'.
 
 
 \end{quote}
 *** Output of to_md ***
-Twas a test to remember in the 90s.
-
-It was in a sense really interesting.
-
-I too met some curly quotes there or
-here No space.
-
-She was 6 12 .
-*** Output of to_s ***
-Twas a test to remember in the 90s.It was  in a sense  really interesting.I  too  met some curly quotes there or hereNo space.She was 612.
-*** EOF ***
-
+	'Twas a "test" to 'remember' in the '90s.
+'Twas a "test" to 'remember' in the '90s.
 
+	It was --- in a sense --- really... interesting.
+It was --- in a sense --- really... interesting.
 
-	OK!
+	I -- too -- met << some curly quotes >> there or <<here>>No space.
+I -- too -- met << some curly quotes >> there or <<here>>No space.
 
 
+	She was 6\"12\'.
+> She was 6\"12\'.
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+*** Output of to_s ***
+Twas a test to remember in the 90s.It was  in a sense  really interesting.I  too  met some curly quotes there or hereNo space.She was 612.
diff --git a/tests/unittest/syntax_hl.md b/spec/block_docs/syntax_hl.md
similarity index 64%
rename from tests/unittest/syntax_hl.md
rename to spec/block_docs/syntax_hl.md
index 30636a2..4a3a25e 100644
--- a/tests/unittest/syntax_hl.md
+++ b/spec/block_docs/syntax_hl.md
@@ -17,21 +17,21 @@ This is ruby code:
 *** Output of inspect ***
 md_el(:document,[
 	md_par(["This is ruby code:"]),
-	md_el(:code,[],{:raw_code=>"require 'maruku'\n\nputs Maruku.new($stdin).to_html"},[]),
+	md_el(:code,[],{:raw_code=>"require 'maruku'\n\nputs Maruku.new($stdin).to_html", :lang=>nil},[]),
 	md_par(["This is ruby code:"]),
-	md_el(:code,[],{:raw_code=>"require 'maruku'"},[["lang", "ruby"], [:ref, "html_use_syntax"]]),
-	md_el(:code,[],{:raw_code=>"puts Maruku.new($stdin).to_html"},[])
+	md_el(:code,[],{:raw_code=>"require 'maruku'", :lang=>nil},[["lang", "ruby"], [:ref, "html_use_syntax"]]),
+	md_el(:code,[],{:raw_code=>"puts Maruku.new($stdin).to_html", :lang=>nil},[])
 ],{},[])
 *** Output of to_html ***
 <p>This is ruby code:</p>
 
-<pre><code>require 'maruku'
+<pre><code>require 'maruku'
 
 puts Maruku.new($stdin).to_html</code></pre>
 
 <p>This is ruby code:</p>
 
-<pre><code class='ruby' lang='ruby'><span class='ident'>require</span> <span class='punct'>'</span><span class='string'>maruku</span><span class='punct'>'</span></code></pre>
+<pre class="ruby"><code class="ruby"><span class="ident">require</span> <span class="punct">'</span><span class="string">maruku</span><span class="punct">'</span></code></pre>
 
 <pre><code>puts Maruku.new($stdin).to_html</code></pre>
 *** Output of to_latex ***
@@ -47,18 +47,14 @@ This is ruby code:
 *** Output of to_md ***
 This is ruby code:
 
-This is ruby code:
-*** Output of to_s ***
-This is ruby code:This is ruby code:
-*** EOF ***
-
-
-
-	OK!
+     require 'maruku'
+     
+     puts Maruku.new($stdin).to_html
 
+This is ruby code:
 
+     require 'maruku'
 
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
+     puts Maruku.new($stdin).to_html
+*** Output of to_s ***
+This is ruby code:This is ruby code:
diff --git a/tests/unittest/table_attributes.md b/spec/block_docs/table_attributes.md
similarity index 56%
rename from tests/unittest/table_attributes.md
rename to spec/block_docs/table_attributes.md
index 93f1b52..bdd36bb 100644
--- a/tests/unittest/table_attributes.md
+++ b/spec/block_docs/table_attributes.md
@@ -3,8 +3,8 @@ Write a comment here
 {} # params 
 *** Markdown input: ***
 
-h         | h
-----------|--
+h         | h 
+----------|---
 {:t}  c1  | c2
 {: summary="Table summary" .class1 style="color:red" border=3 width="50%" frame=lhs rules=cols  cellspacing=2em cellpadding=4px}
 
@@ -12,16 +12,14 @@ h         | h
 *** Output of inspect ***
 md_el(:document,[
 	md_el(:table,[
-		md_el(:head_cell,["h"],{},[]),
-		md_el(:head_cell,["h"],{},[]),
-		md_el(:cell,[" c1"],{},[[:ref, "t"]]),
-		md_el(:cell,["c2"],{},[])
+		[md_el(:head_cell,["h"],{},[]),md_el(:head_cell,["h"],{},[])],
+		[md_el(:cell,[" c1"],{},[[:ref, "t"]]),md_el(:cell,["c2"],{},[])]
 	],{:align=>[:left, :left]},[["summary", "Table summary"], [:class, "class1"], ["style", "color:red"], ["border", "3"], ["width", "50%"], ["frame", "lhs"], ["rules", "cols"], ["cellspacing", "2em"], ["cellpadding", "4px"]]),
 	md_el(:ald,[],{:ald=>[["scope", "row"]],:ald_id=>"t"},[])
 ],{},[])
 *** Output of to_html ***
-<table cellspacing='2em' class='class1' border='3' rules='cols' frame='lhs' summary='Table summary' cellpadding='4px' width='50%' style='color:red'><thead><tr><th>h</th><th>h</th></tr></thead><tbody><tr><th scope='row' style='text-align: left;'> c1</th><td style='text-align: left;'>c2</td>
-</tr></tbody></table>
+<table class="class1" style="color:red" summary="Table summary" width="50%" frame="lhs" rules="cols" border="3" cellspacing="2em" cellpadding="4px"><thead><tr><th>h</th><th>h</th></tr></thead><tbody><tr><th scope="row" style="text-align: left;"> c1</th><td style="text-align: left;">c2</td></tr>
+</tbody></table>
 *** Output of to_latex ***
 \begin{tabular}{l|l}
 h&h\\
@@ -32,15 +30,3 @@ h&h\\
 hh c1c2
 *** Output of to_s ***
 hh c1c2
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/table_colspan.md b/spec/block_docs/table_colspan.md
new file mode 100644
index 0000000..345fb71
--- /dev/null
+++ b/spec/block_docs/table_colspan.md
@@ -0,0 +1,41 @@
+Write a comment here
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+
+| h1        | h2  |   h3 |
+|:----------|:---:|-----:|
+|c1         | c2  |  c3  |
+|c1         | c2         ||
+|c1         ||       c2  |
+|c1                      |||
+{: summary="Table summary" .class1 style="color:blue" border=1 width="50%" cellspacing=2em cellpadding=4px}
+
+{:t: scope="row"}
+*** Output of inspect ***
+md_el(:document,[
+	md_el(:table, [
+       	[md_el(:head_cell, "h1"), md_el(:head_cell, "h2"), md_el(:head_cell, "h3")],
+       	[md_el(:cell, "c1"), md_el(:cell, "c2"), md_el(:cell, "c3")],
+       	[md_el(:cell, "c1"), md_el(:cell, "c2", {}, [["colspan", "2"]])],
+       	[md_el(:cell, "c1", {}, [["colspan", "2"]]), md_el(:cell, "c2")],
+       	[md_el(:cell, "c1", {}, [["colspan", "3"]])]
+       ],{:align=>[:left, :center, :right]},[["summary", "Table summary"], [:class, "class1"], ["style", "color:blue"], ["border", ""], ["width", "50%"], ["frame", "lhs"], ["rules", "cols"], ["cellspacing", "2em"], ["cellpadding", "4px"]]),
+	md_el(:ald,[],{:ald=>[["scope", "row"]],:ald_id=>"t"},[])
+],{},[])
+*** Output of to_html ***
+<table class="class1" style="color:blue" summary="Table summary" width="50%" border="1" cellspacing="2em" cellpadding="4px">
+<thead><tr><th>h1</th><th>h2</th><th>h3</th></tr></thead>
+<tbody><tr><td style="text-align: left;">c1</td><td style="text-align: center;">c2</td><td style="text-align: right;">c3</td></tr>
+<tr><td style="text-align: left;">c1</td><td colspan="2" style="text-align: center;">c2</td></tr>
+<tr><td colspan="2" style="text-align: left;">c1</td><td style="text-align: center;">c2</td></tr>
+<tr><td colspan="3" style="text-align: left;">c1</td></tr></tbody></table>
+*** Output of to_latex ***
+\begin{tabular}{l|c|r}
+h1&h2&h3\\
+\hline 
+c1&c2&c3\\
+c1&\multicolumn {2}{|l|}{c2}\\
+\multicolumn {2}{|l|}{c1}&c2\\
+\multicolumn {3}{|l|}{c1}\\
+\end{tabular}
diff --git a/spec/block_docs/tables.md b/spec/block_docs/tables.md
new file mode 100644
index 0000000..b6462bc
--- /dev/null
+++ b/spec/block_docs/tables.md
@@ -0,0 +1,47 @@
+PHP Markdown Extra table syntax
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+
+Col1    | Very very long head | Very very long head|
+------- |:-------------------:|-------------------:|
+cell    | center-align        | right-align        |
+another | cell                | here               |
+
+| First Header  | Second Header |
+| ------------- | ------------- |
+| Content Cell  | Content Cell  |
+| Content Cell  | Content Cell  |
+
+First Header  | Second Header
+------------- | -------------
+Content Cell  | Content Cell
+Content Cell  | Content Cell
+
+*** Output of inspect ***
+md_el(:document, [
+	md_el(:table, [
+	[md_el(:head_cell, "Col1"), md_el(:head_cell, "Very very long head"), md_el(:head_cell, "Very very long head")],
+	[md_el(:cell, "cell"), md_el(:cell, "center-align"), md_el(:cell, "right-align")],
+	[md_el(:cell, "another"), md_el(:cell, "cell"), md_el(:cell, "here")]
+], {:align=>[:left, :center, :right]}),
+	md_el(:table, [
+	[md_el(:head_cell, "First Header"), md_el(:head_cell, "Second Header")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")]
+], {:align=>[:left, :left]}),
+	md_el(:table, [
+	[md_el(:head_cell, "First Header"), md_el(:head_cell, "Second Header")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")]
+], {:align=>[:left, :left]})
+])
+*** Output of to_html ***
+<table><thead><tr><th>Col1</th><th>Very very long head</th><th>Very very long head</th></tr></thead><tbody><tr><td style="text-align: left;">cell</td><td style="text-align: center;">center-align</td><td style="text-align: right;">right-align</td></tr>
+<tr><td style="text-align: left;">another</td><td style="text-align: center;">cell</td><td style="text-align: right;">here</td></tr>
+</tbody></table><table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+</tbody></table><table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+</tbody></table>
+
diff --git a/spec/block_docs/tables2.md b/spec/block_docs/tables2.md
new file mode 100644
index 0000000..73cf82c
--- /dev/null
+++ b/spec/block_docs/tables2.md
@@ -0,0 +1,74 @@
+Trailing blanks in table rows
+*** Parameters: ***
+{} # params 
+*** Markdown input: ***
+
+Col1    | Very very long head | Very very long head| 
+------- |:-------------------:|-------------------:|
+cell    | center-align        | right-align        |
+another | cell                | here               |
+
+| First Header  | Second Header |
+| ------------- | ------------- | 
+| Content Cell  | Content Cell  |
+| Content Cell  | Content Cell  |
+
+| First Header  | Second Header |
+| ------------- | ------------- |
+| Content Cell  | Content Cell  | 
+| Content Cell  | Content Cell  |
+
+First Header  | Second Header|
+------------- | -------------|
+Content Cell  | Content Cell| 
+Content Cell  | Content Cell|
+
+First Header  | Second Header
+------------- | -------------
+Content Cell  | Content Cell
+Content Cell  |  
+Content Cell  | Content Cell
+
+*** Output of inspect ***
+md_el(:document, [
+	md_el(:table, [
+	[md_el(:head_cell, "Col1"), md_el(:head_cell, "Very very long head"), md_el(:head_cell, "Very very long head")],
+	[md_el(:cell, "cell"), md_el(:cell, "center-align"), md_el(:cell, "right-align")],
+	[md_el(:cell, "another"), md_el(:cell, "cell"), md_el(:cell, "here")]
+], {:align=>[:left, :center, :right]}),
+	md_el(:table, [
+	[md_el(:head_cell, "First Header"), md_el(:head_cell, "Second Header")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")]
+], {:align=>[:left, :left]}),
+	md_el(:table, [
+	[md_el(:head_cell, "First Header"), md_el(:head_cell, "Second Header")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")]
+], {:align=>[:left, :left]}),
+	md_el(:table, [
+	[md_el(:head_cell, "First Header"), md_el(:head_cell, "Second Header")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")]
+], {:align=>[:left, :left]}),
+	md_el(:table, [
+	[md_el(:head_cell, "First Header"), md_el(:head_cell, "Second Header")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")],
+	[md_el(:cell, "Content Cell"), md_el(:cell, [])],
+	[md_el(:cell, "Content Cell"), md_el(:cell, "Content Cell")]
+], {:align=>[:left, :left]})
+])
+*** Output of to_html ***
+<table><thead><tr><th>Col1</th><th>Very very long head</th><th>Very very long head</th></tr></thead><tbody><tr><td style="text-align: left;">cell</td><td style="text-align: center;">center-align</td><td style="text-align: right;">right-align</td></tr>
+<tr><td style="text-align: left;">another</td><td style="text-align: center;">cell</td><td style="text-align: right;">here</td></tr>
+</tbody></table><table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+</tbody></table><table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+</tbody></table><table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+</tbody></table><table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;"></td></tr>
+<tr><td style="text-align: left;">Content Cell</td><td style="text-align: left;">Content Cell</td></tr>
+</tbody></table>
+
diff --git a/tests/unittest/test.md b/spec/block_docs/test.md
similarity index 73%
rename from tests/unittest/test.md
rename to spec/block_docs/test.md
index e1af3ee..028066e 100644
--- a/tests/unittest/test.md
+++ b/spec/block_docs/test.md
@@ -8,7 +8,7 @@ Write a comment abouth the test here.
 
 
 *** Output of inspect ***
-md_el(:document,[md_el(:code,[],{:raw_code=>"       $ python       "},[])],{},[])
+md_el(:document,[md_el(:code,[],{:raw_code=>"       $ python       ", :lang=>nil},[])],{},[])
 *** Output of to_html ***
 <pre><code>       $ python       </code></pre>
 *** Output of to_latex ***
@@ -17,15 +17,3 @@ md_el(:document,[md_el(:code,[],{:raw_code=>"       $ python       "},[])],{},[]
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/notyet/ticks.md b/spec/block_docs/ticks.md
similarity index 63%
rename from tests/unittest/notyet/ticks.md
rename to spec/block_docs/ticks.md
index e3d6d82..f9ce8a4 100644
--- a/tests/unittest/notyet/ticks.md
+++ b/spec/block_docs/ticks.md
@@ -11,20 +11,8 @@ md_el(:document,[md_par([md_code("There is a literal backtick (`) here.")])],{},
 *** Output of to_html ***
 <p><code>There is a literal backtick (`) here.</code></p>
 *** Output of to_latex ***
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt There~is~a~literal~backtick~\char40\char96\char41~here\char46}}
+{\colorbox[rgb]{1.00,0.93,1.00}{\tt There\char32is\char32a\char32literal\char32backtick\char32\char40\char96\char41\char32here\char46}}
 *** Output of to_md ***
 
 *** Output of to_s ***
 
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/toc.md b/spec/block_docs/toc.md
new file mode 100644
index 0000000..956de6b
--- /dev/null
+++ b/spec/block_docs/toc.md
@@ -0,0 +1,87 @@
+Write a comment abouth the test here.
+*** Parameters: ***
+{:use_numbered_headers => true}
+*** Markdown input: ***
+
+* Table of Contents
+{:toc}
+
+A title with *emphasis*
+=======================
+
+## Try ## {#try}
+
+First Subheader
+---------------
+{#foo}
+
+Say something.
+
+### A title with *emphasis* ###
+
+Say something else.
+
+Second Subheader
+--------------
+
+You don't say.
+
+*** Output of inspect ***
+md_el(:document,[
+    md_el(:ul, md_el(:li, "Table of Contents", {:want_my_paragraph=>false}), {}, [[:ref, "toc"]]),
+	md_el(:header,["A title with ", md_em(["emphasis"])],{:level=>1},[]),
+	md_el(:header, "Try", {:level=>2}, [[:id, "try"]]),
+	md_el(:header, "First Subheader", {:level=>2}),
+	md_par("Say something."),
+	md_el(:header, ["A title with ", md_em("emphasis")], {:level=>3}),
+	md_par("Say something else."),
+	md_el(:header, "Second Subheader", {:level=>2}),
+	md_par(["You don", md_entity("rsquo"), "t say."])
+],{},[])
+*** Output of to_html ***
+<div class="maruku_toc"><ul><li><span class="maruku_section_number">1. </span><a href="#try">Try</a></li><li><span class="maruku_section_number">2. </span><a href="#foo">First Subheader</a><ul><li><span class="maruku_section_number">2.1. </span><a href="#a_title_with_emphasis_2">A title with <em>emphasis</em></a></li></ul></li><li><span class="maruku_section_number">3. </span><a href="#second_subheader">Second Subheader</a></li></ul></div>
+<h1 id="a_title_with_emphasis">A title with <em>emphasis</em></h1>
+
+<h2 id="try"><span class="maruku_section_number">1. </span>Try</h2>
+
+<h2 id="foo"><span class="maruku_section_number">2. </span>First Subheader</h2>
+
+<p>Say something.</p>
+
+<h3 id="a_title_with_emphasis_2"><span class="maruku_section_number">2.1. </span>A title with <em>emphasis</em></h3>
+
+<p>Say something else.</p>
+
+<h2 id="second_subheader"><span class="maruku_section_number">3. </span>Second Subheader</h2>
+
+<p>You don’t say.</p>
+*** Output of to_latex ***
+\noindent1. \hyperlink{try}{Try}\dotfill \pageref*{try} \linebreak
+\noindent2. \hyperlink{foo}{First Subheader}\dotfill \pageref*{foo} \linebreak
+\noindent2.1. \hyperlink{a_title_with_emphasis_2}{A title with \emph{emphasis}}\dotfill \pageref*{a_title_with_emphasis_2} \linebreak
+\noindent3. \hyperlink{second_subheader}{Second Subheader}\dotfill \pageref*{second_subheader} \linebreak
+
+
+\hypertarget{a_title_with_emphasis}{}\section*{{A title with \emph{emphasis}}}\label{a_title_with_emphasis}
+
+\hypertarget{try}{}\subsection*{{1. Try}}\label{try}
+
+\hypertarget{foo}{}\subsection*{{2. First Subheader}}\label{foo}
+
+Say something.
+
+\hypertarget{a_title_with_emphasis_2}{}\subsubsection*{{2.1. A title with \emph{emphasis}}}\label{a_title_with_emphasis_2}
+
+Say something else.
+
+\hypertarget{second_subheader}{}\subsection*{{3. Second Subheader}}\label{second_subheader}
+
+You don't say.
+*** Output of to_md ***
+# A title with *emphasis* #
+
+## A title with *emphasis* ##
+
+#### A title with *emphasis* ####
+*** Output of to_s ***
+A title with emphasisA title with emphasisA title with emphasis
diff --git a/tests/unittest/notyet/triggering.md b/spec/block_docs/triggering.md
similarity index 87%
rename from tests/unittest/notyet/triggering.md
rename to spec/block_docs/triggering.md
index 92f85cd..837841a 100644
--- a/tests/unittest/notyet/triggering.md
+++ b/spec/block_docs/triggering.md
@@ -30,11 +30,11 @@ Paragraph with block quote:
 > Quoted
 
 Paragraph with header:
-### header ###
+### header 1 ###
 
 Paragraph with header on two lines:
-header
-------
+header 2
+--------
 
 *** Output of inspect ***
 md_el(:document,[
@@ -57,9 +57,9 @@ md_el(:document,[
 	md_par(["Paragraph with block quote:"]),
 	md_el(:quote,[md_par(["Quoted"])],{},[]),
 	md_par(["Paragraph with header:"]),
-	md_el(:header,["header"],{:level=>3},[]),
+	md_el(:header,["header 1"],{:level=>3},[]),
 	md_par(["Paragraph with header on two lines:"]),
-	md_el(:header,["header"],{:level=>2},[])
+	md_el(:header,["header 2"],{:level=>2},[])
 ],{},[])
 *** Output of to_html ***
 <p>Paragraph, list with no space: * ciao</p>
@@ -86,11 +86,11 @@ md_el(:document,[
 
 <p>Paragraph with header:</p>
 
-<h3 id='header'>header</h3>
+<h3 id="header_1">header 1</h3>
 
 <p>Paragraph with header on two lines:</p>
 
-<h2 id='header'>header</h2>
+<h2 id="header_2">header 2</h2>
 *** Output of to_latex ***
 Paragraph, list with no space: * ciao
 
@@ -117,11 +117,11 @@ Quoted
 \end{quote}
 Paragraph with header:
 
-\hypertarget{header}{}\subsubsection*{{header}}\label{header}
+\hypertarget{header_1}{}\subsubsection*{{header 1}}\label{header_1}
 
 Paragraph with header on two lines:
 
-\hypertarget{header}{}\subsection*{{header}}\label{header}
+\hypertarget{header_2}{}\subsection*{{header 2}}\label{header_2}
 *** Output of to_md ***
 Paragraph, list with no space: * ciao
 
@@ -146,24 +146,13 @@ no space:
 
 Paragraph with block quote:
 
-Quoted
-
+> Quoted
 Paragraph with header:
 
-headerParagraph with header on two lines:
+### header
 
-header
+Paragraph with header on two lines:
+
+## header
 *** Output of to_s ***
 Paragraph, list with no space: * ciaoParagraph, list with 1 space: * ciaoParagraph, list with 3 space: * ciaoParagraph, list with 4 spaces: * ciaoParagraph, list with 1 tab: * ciaoParagraph (1 space after), list with no space: * ciaoParagraph (2 spaces after), list with no space:* ciaoParagraph (3 spaces after), list with no space: * ciaoParagraph with block quote:QuotedParagraph with header:headerParagraph with header on two lines:header
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/underscore_in_words.md b/spec/block_docs/underscore_in_words.md
similarity index 78%
rename from tests/unittest/underscore_in_words.md
rename to spec/block_docs/underscore_in_words.md
index 8b342e4..2b6f84b 100644
--- a/tests/unittest/underscore_in_words.md
+++ b/spec/block_docs/underscore_in_words.md
@@ -13,15 +13,3 @@ Ok, this\_was a\_really\_old bug
 Ok, this_was a_really_old bug
 *** Output of to_s ***
 Ok, this_was a_really_old bug
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/wrapping.md b/spec/block_docs/wrapping.md
similarity index 94%
rename from tests/unittest/wrapping.md
rename to spec/block_docs/wrapping.md
index 8624700..59277e4 100644
--- a/tests/unittest/wrapping.md
+++ b/spec/block_docs/wrapping.md
@@ -18,12 +18,12 @@ md_el(:document,[
 		"Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet."
 	]),
 	md_el(:ul,[
-		md_el(:li_span,[
+		md_el(:li,[
 			"Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet Lorem ipsum Break:",
 			md_el(:linebreak,[],{},[]),
 			"Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet"
 		],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[
+		md_el(:li,[
 			"Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet"
 		],{:want_my_paragraph=>false},[])
 	],{},[])
@@ -54,26 +54,14 @@ Lorem ipsum dolor amet. Lorem ipsum
 dolor amet. Lorem ipsum dolor amet.
 Lorem ipsum dolor amet.
 
--orem ipsum dolor amet. Lorem ipsum
+- Lorem ipsum dolor amet. Lorem ipsum
 dolor amet. Lorem ipsum dolor amet.
 Lorem ipsum dolor amet Lorem ipsum
 Break:  
 Lorem ipsum dolor amet. Lorem ipsum
 dolor amet. Lorem ipsum dolor amet
--orem ipsum dolor amet. Lorem ipsum
+- Lorem ipsum dolor amet. Lorem ipsum
 dolor amet. Lorem ipsum dolor amet.
 Lorem ipsum dolor amet
 *** Output of to_s ***
 Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Break:Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet.Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor amet Lorem ipsum Break:Lorem ipsum dolor amet. Lorem ipsum dolor amet. Lorem ipsum dolor ametLorem ipsum dolor amet. Lorem ipsum dolo [...]
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_docs/xml.md b/spec/block_docs/xml.md
new file mode 100644
index 0000000..4b2e280
--- /dev/null
+++ b/spec/block_docs/xml.md
@@ -0,0 +1,33 @@
+JRUBY NOKOGIRI PENDING - Write a comment here
+(JRuby Nokogiri is broken for empty tags: https://github.com/sparklemotion/nokogiri/issues/971)
+*** Parameters: ***
+{:on_error=>:raise}
+*** Markdown input: ***
+
+<svg/>
+
+<svg:svg xmlns:svg="http://www.w3.org/2000/svg"
+width="600px" height="400px">
+  <svg:g id="group">
+	<svg:circle id="circ1" r="1cm" cx="3cm" cy="3cm" style="fill:red;"></svg:circle>
+	<svg:circle id="circ2" r="1cm" cx="7cm" cy="3cm" style="fill:red;" />
+  </svg:g>
+</svg:svg>
+
+*** Output of inspect ***
+md_el(:document,[
+	md_html("<svg/>"),
+	md_html("<svg:svg xmlns:svg=\"http://www.w3.org/2000/svg\"\nwidth=\"600px\" height=\"400px\">\n  <svg:g id=\"group\">\n\t<svg:circle id=\"circ1\" r=\"1cm\" cx=\"3cm\" cy=\"3cm\" style=\"fill:red;\"></svg:circle>\n\t<svg:circle id=\"circ2\" r=\"1cm\" cx=\"7cm\" cy=\"3cm\" style=\"fill:red;\" />\n  </svg:g>\n</svg:svg>")
+],{},[])
+*** Output of to_html ***
+<svg></svg><svg:svg xmlns:svg="http://www.w3.org/2000/svg" width="600px" height="400px">
+  <svg:g id="group">
+	<svg:circle id="circ1" r="1cm" cx="3cm" cy="3cm" style="fill:red;"></svg:circle>
+	<svg:circle id="circ2" r="1cm" cx="7cm" cy="3cm" style="fill:red;"></svg:circle>
+  </svg:g>
+</svg:svg>
+*** Output of to_latex ***
+
+*** Output of to_md ***
+
+*** Output of to_s ***
diff --git a/spec/block_docs/xml3.md b/spec/block_docs/xml3.md
new file mode 100644
index 0000000..4c15087
--- /dev/null
+++ b/spec/block_docs/xml3.md
@@ -0,0 +1,24 @@
+The markdown="1" attribute does NOT get recursively applied
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<table markdown='1'>
+	Blah
+	<thead>
+		<tr><td>*em*</td></tr>
+	</thead>
+</table>
+
+*** Output of inspect ***
+md_el(:document,[
+	md_html("<table markdown='1'>\n\tBlah\n\t<thead>\n\t\t<tr><td>*em*</td></tr>\n\t</thead>\n</table>")
+],{},[])
+*** Output of to_html ***
+<table>
+	Blah
+	<thead>
+		<tr><td>*em*</td></tr>
+	</thead>
+</table>
+
+
diff --git a/spec/block_docs/xml_comments.md b/spec/block_docs/xml_comments.md
new file mode 100644
index 0000000..bc779df
--- /dev/null
+++ b/spec/block_docs/xml_comments.md
@@ -0,0 +1,32 @@
+XML Comments need to be handled properly.
+Note that output is kind of weird because we modify the comment in order to let REXML parse it due to https://bugs.ruby-lang.org/issues/9277.
+*** Parameters: ***
+{}
+*** Markdown input: ***
+<!--
+’
+-->
+
+<!-- declarations for <head> & <body> -->
+
+<!-- -- is invalid -->
+
+<!-- -- is
+invalid -->
+
+*** Output of inspect ***
+md_el(:document,[md_html("<!--\n’\n-->"),
+	md_html("<!-- declarations for <head> & <body> -->"),
+	md_html("<!-- - - is invalid -->"),
+	md_html("<!-- - - is\ninvalid -->")])
+*** Output of to_html ***
+<!--
+’
+-->
+
+<!-- declarations for <head> & <body> -->
+
+<!-- - - is invalid -->
+
+<!-- - - is
+invalid -->
diff --git a/tests/unittest/xml_instruction.md b/spec/block_docs/xml_instruction.md
similarity index 71%
rename from tests/unittest/xml_instruction.md
rename to spec/block_docs/xml_instruction.md
index 5f89afd..ec7d239 100644
--- a/tests/unittest/xml_instruction.md
+++ b/spec/block_docs/xml_instruction.md
@@ -3,12 +3,12 @@ Directives should be preserved.
 {}
 *** Markdown input: ***
 
-<? noTarget?> 
-<?php ?> 
-<?xml ?> 
+<? noTarget?>
+<?php ?>
+<?xml ?>
 <?mrk ?>
 
-Targets <? noTarget?> <?php ?> <?xml ?> <?mrk ?>
+Targets <? noTarget?> <?php ?> <?xml ?> <?mrk ?> !
 
 Inside: <?mrk puts "Inside: Hello" ?> last
 
@@ -27,7 +27,8 @@ md_el(:document,[
 		" ",
 		md_el(:xml_instr,[],{:code=>"",:target=>"xml"},[]),
 		" ",
-		md_el(:xml_instr,[],{:code=>"",:target=>"mrk"},[])
+		md_el(:xml_instr,[],{:code=>"",:target=>"mrk"},[]),
+    " !"
 	]),
 	md_par([
 		"Inside: ",
@@ -36,12 +37,12 @@ md_el(:document,[
 	])
 ],{},[])
 *** Output of to_html ***
-<? noTarget?><?php ?><?xml ?><?mrk ?>
-<p>Targets <? noTarget?> <?php ?> <?xml ?> <?mrk ?></p>
+<? noTarget?><?php ?><?xml ?><?mrk ?>
+<p>Targets <?noTarget?> <?php ?> <?xml ?> <?mrk ?> !</p>
 
 <p>Inside: <?mrk puts "Inside: Hello"?> last</p>
 *** Output of to_latex ***
-Targets    
+Targets     !
 
 Inside:  last
 *** Output of to_md ***
@@ -50,15 +51,3 @@ Targets
 Inside: last
 *** Output of to_s ***
 Targets    Inside:  last
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/spec/block_spec.rb b/spec/block_spec.rb
new file mode 100644
index 0000000..d0a3735
--- /dev/null
+++ b/spec/block_spec.rb
@@ -0,0 +1,110 @@
+# encoding: UTF-8
+Encoding.default_external=('UTF-8') if ''.respond_to?(:force_encoding)
+
+require File.dirname(__FILE__) + '/spec_helper'
+require 'rspec'
+require 'maruku'
+require 'nokogiri/diff'
+
+# Allow us to test both HTML parser backends
+MaRuKu::Globals[:html_parser] = ENV['HTML_PARSER'] if ENV['HTML_PARSER']
+
+puts "Using HTML parser: #{MaRuKu::Globals[:html_parser]}"
+
+# :to_md and :to_s tests are disabled for now
+METHODS = [:to_html, :to_latex]
+
+def which(cmd)
+  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
+  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
+    exts.each { |ext|
+      exe = File.join(path, "#{cmd}#{ext}")
+      return exe if File.executable? exe
+    }
+  end
+  return nil
+end
+
+if which('blahtex')
+  HAS_BLAHTEX = true
+else
+  HAS_BLAHTEX = false
+  puts "Install 'blahtex' to run blahtex math tests"
+end
+
+describe "A Maruku doc" do
+  before(:all) do
+    @old_stderr = $stderr
+    $stderr = StringIO.new
+  end
+
+  after(:all) do
+    $stderr = @old_stderr
+  end
+
+  Dir[File.dirname(__FILE__) + "/block_docs/**/*.md"].each do |md|
+    next if md =~ /blahtex/ && !HAS_BLAHTEX
+
+    md_pretty = md.sub(File.dirname(__FILE__) + '/', '')
+
+    describe "#{md_pretty} (using #{MaRuKu::Globals[:html_parser]})" do
+      input = File.read(md).split(/\n\*{3}[^*\n]+\*{3}\n/m)
+      input = ["Write a comment here", "{}", input.first] if input.size == 1
+      comment = input.shift.strip
+      params = input.shift || ''
+      markdown = input.shift || ''
+      ast = input.shift || ''
+      expected = METHODS.zip(input).inject({}) {|h, (k, v)| h[k] = v ? v.strip : '' ; h}
+
+      pending "#{comment} - #{md_pretty}" and next if comment.start_with?("PENDING")
+      pending "#{comment} - #{md_pretty}" and next if comment.start_with?("REXML PENDING") && MaRuKu::Globals[:html_parser] == 'rexml'
+      pending "#{comment} - #{md_pretty}" and next if comment.start_with?("JRUBY PENDING") && RUBY_PLATFORM == 'java'
+      pending "#{comment} - #{md_pretty}" and next if comment.start_with?("JRUBY NOKOGIRI PENDING") && RUBY_PLATFORM == 'java' && MaRuKu::Globals[:html_parser] == 'nokogiri'
+
+      before(:each) do
+        $already_warned_itex2mml = false
+        @doc = Maruku.new(markdown, eval(params))
+      end
+
+      it "should read in the output of #inspect as the same document" do
+        Maruku.new.instance_eval("#coding: utf-8\n#{@doc.inspect}", md).should == @doc
+      end
+
+      unless ast.strip.empty?
+        it "should produce the given AST" do
+          @doc.should == Maruku.new.instance_eval(ast, md)
+        end
+      end
+
+      unless expected[:to_html].strip.empty?
+        it "should have the expected to_html output" do
+          res = @doc.to_html.strip
+          pending "install itex2mml to run these tests" if $already_warned_itex2mml
+
+          resdoc = Nokogiri::XML("<dummy>#{res}</dummy>")
+          expdoc = Nokogiri::XML("<dummy>#{expected[:to_html]}</dummy>")
+
+          diff = ""
+          changed = false
+          expdoc.diff(resdoc) do |change, node|
+            diff << "#{change} #{node.inspect}\n"
+            changed = true unless change == ' ' || (node.text? && node.content =~ /\A\s*\Z/m)
+          end
+
+          if changed
+            res.should == expected[:to_html]
+          end
+        end
+      end
+
+      unless expected[:to_latex].strip.empty?
+        it "should have the expected to_latex output" do
+          res = @doc.to_latex.strip
+          res.should == expected[:to_latex]
+        end
+      end
+    end
+  end
+
+
+end
diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb
new file mode 100644
index 0000000..5ad7947
--- /dev/null
+++ b/spec/cli_spec.rb
@@ -0,0 +1,8 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe "The maruku CLI" do
+  it "has a nonzero exit code on invalid options" do
+    `ruby -Ilib bin/maruku --foo 2>&1`
+    $?.exitstatus.should_not == 0
+  end
+end
diff --git a/spec/span_spec.rb b/spec/span_spec.rb
new file mode 100644
index 0000000..da0aa7a
--- /dev/null
+++ b/spec/span_spec.rb
@@ -0,0 +1,256 @@
+require File.dirname(__FILE__) + '/spec_helper'
+require 'rspec'
+require 'maruku'
+
+EXPECTATIONS = Maruku.new.instance_eval do
+  [
+    ["",       [],         'Empty string gives empty list'],
+    ["a",      ["a"],      'Easy char'],
+    [" a",     ["a"],      'First space in the paragraph is ignored'],
+    ["a\n \n", ["a"],      'Last spaces in the paragraphs are ignored'],
+    [' ',      [],      'One char => nothing'],
+    ['  ',     [],      'Two chars => nothing'],
+    ['a  b',   ['a b'],    'Spaces are compressed'],
+    ['a  b',   ['a b'],    'Newlines are spaces'],
+    ["a\nb",   ['a b'],    'Newlines are spaces'],
+    ["a\n b",  ['a b'],    'Compress newlines 1'],
+    ["a \nb",  ['a b'],    'Compress newlines 2'],
+    [" \nb",   ['b'],      'Compress newlines 3'],
+    ["\nb",    ['b'],      'Compress newlines 4'],
+    ["b\n",    ['b'],     'Compress newlines 5'],
+    ["\n",     [],      'Compress newlines 6'],
+    ["\n\n\n", [],      'Compress newlines 7'],
+
+    # Code blocks
+    ["`" ,   :raise,  'Unclosed single ticks'],
+    ["``" ,  [md_entity("ldquo")],  'Empty code block'],
+    ["`a`" ,     [md_code('a')],    'Simple inline code'],
+    ["`` ` ``" ,    [md_code('`')],   ],
+    ["`` \\` ``" ,    [md_code('\\`')],   ],
+    ["``a``" ,   [md_code('a')],    ],
+    ["`` a ``" ,   [md_code('a')],    ],
+
+    # Newlines
+    ["a  \n", ['a',md_el(:linebreak)], 'Two spaces give br.'],
+    ["a \n",  ['a'], 'Newlines 2'],
+    ["  \n",  [md_el(:linebreak)], 'Newlines 3'],
+    ["  \n  \n",  [md_el(:linebreak),md_el(:linebreak)],'Newlines 4'],
+    ["  \na  \n",  [md_el(:linebreak),'a',md_el(:linebreak)],'Newlines 5'],
+
+    # Inline HTML
+    ["a < b", ['a < b'], '< can be on itself'],
+    ["<hr>",  [md_html('<hr />')], 'HR will be sanitized'],
+    ["<hr/>", [md_html('<hr />')], 'Closed tag is ok'],
+    ["<hr  />", [md_html('<hr />')], 'Closed tag is ok 2'],
+    ["<hr/>a", [md_html('<hr />'),'a'], 'Closed tag is ok 2'],
+    ["<em></em>a", [md_html('<em></em>'),'a'], 'Inline HTML 1'],
+    ["<em>e</em>a", [md_html('<em>e</em>'),'a'], 'Inline HTML 2'],
+    ["a<em>e</em>b", ['a',md_html('<em>e</em>'),'b'], 'Inline HTML 3'],
+    ["<em>e</em>a<em>f</em>",
+      [md_html('<em>e</em>'),'a',md_html('<em>f</em>')],
+      'Inline HTML 4'],
+    ["<em>e</em><em>f</em>a",
+      [md_html('<em>e</em>'),md_html('<em>f</em>'),'a'],
+      'Inline HTML 5'],
+
+    ["<img src='a' />", [md_html("<img src='a' />")], 'Attributes'],
+    ["<img src='a'/>"],
+
+    # emphasis
+    ["**", :raise, 'Unclosed double **'],
+    ["\\*", ['*'], 'Escaping of *'],
+    ["a *b* ", ['a ', md_em('b')], 'Emphasis 1'],
+    ["a *b*", ['a ', md_em('b')], 'Emphasis 2'],
+    ["a * b", ['a * b'], 'Emphasis 3'],
+    ["a * b*", :raise, 'Unclosed emphasis'],
+    # same with underscore
+    ["__", :raise, 'Unclosed double __'],
+    ["\\_", ['_'], 'Escaping of _'],
+    ["a _b_ ", ['a ', md_em('b')], 'Emphasis 4'],
+    ["a _b_", ['a ', md_em('b')], 'Emphasis 5'],
+    ["a _ b", ['a _ b'], 'Emphasis 6'],
+    ["a _ b_", :raise, 'Unclosed emphasis'],
+    ["_b_", [md_em('b')], 'Emphasis 7'],
+    ["_b_ _c_", [md_em('b'),' ',md_em('c')], 'Emphasis 8'],
+    ["_b__c_", [md_em('b'),md_em('c')], 'Emphasis 9', true], # PENDING
+    # underscores in word
+    ["mod_ruby", ['mod_ruby'], 'Word with underscore'],
+    # strong
+    ["**a*", :raise, 'Unclosed double ** 2'],
+    ["\\**a*", ['*', md_em('a')], 'Escaping of *'],
+    ["a **b** ", ['a ', md_strong('b')], 'Emphasis 1'],
+    ["a **b**", ['a ', md_strong('b')], 'Emphasis 2'],
+    ["a ** b", ['a ** b'], 'Emphasis 3'],
+    ["a ** b**", :raise, 'Unclosed emphasis'],
+    ["**b****c**", [md_strong('b'),md_strong('c')], 'Emphasis 9'],
+    ["*italic***bold***italic*", [md_em('italic'), md_strong('bold'), md_em('italic')], 'Bold inbetween italics'], # Issue #103
+    # strong (with underscore)
+    ["__a_", :raise, 'Unclosed double __ 2'],
+
+    ["a __b__ ", ['a ', md_strong('b')], 'Emphasis 1'],
+    ["a __b__", ['a ', md_strong('b')], 'Emphasis 2'],
+    ["a __ b", ['a __ b'], 'Emphasis 3'],
+    ["a __ b__", :raise, 'Unclosed emphasis'],
+    ["__b____c__", [md_strong('b'),md_strong('c')], 'Emphasis 9'],
+    # extra strong
+    ["***a**", :raise, 'Unclosed triple *** '],
+    ["\\***a**", ['*', md_strong('a')], 'Escaping of *'],
+    ["a ***b*** ", ['a ', md_emstrong('b')], 'Strong elements'],
+    ["a ***b***", ['a ', md_emstrong('b')]],
+    ["a *** b", ['a *** b']],
+    ["a ** * b", ['a ** * b']],
+    ["***b******c***", [md_emstrong('b'),md_emstrong('c')]],
+    ["a *** b***", :raise, 'Unclosed emphasis'],
+    # same with underscores
+    ["___a__", :raise, 'Unclosed triple *** '],
+    ["a ___b___ ", ['a ', md_emstrong('b')], 'Strong elements'],
+    ["a ___b___", ['a ', md_emstrong('b')]],
+    ["a ___ b", ['a ___ b']],
+    ["a __ _ b", ['a __ _ b']],
+    ["___b______c___", [md_emstrong('b'),md_emstrong('c')]],
+    ["a ___ b___", :raise, 'Unclosed emphasis'],
+    # mixing is bad
+    ["*a_", :raise, 'Mixing is bad'],
+    ["_a*", :raise],
+    ["**a__", :raise],
+    ["__a**", :raise],
+    ["___a***", :raise],
+    ["***a___", :raise],
+    ["*This is in italic, and this is **bold**.*", [md_em(["This is in italic, and this is ", md_strong("bold"), "."])], 'Issue #23'],
+
+    # links of the form [text][ref]
+    ["\\[a]",  ["[a]"], 'Escaping 1'],
+    ["\\[a\\]", ["[a]"], 'Escaping 2'],
+    # This is valid in the new Markdown version
+    ["[a]",   [ md_link(["a"],nil)], 'Empty link'],
+    ["[a][]", [ md_link(["a"],'')] ],
+    ["[a][]b",   [ md_link(["a"],''),'b'], 'Empty link'],
+    ["[a\\]][]", [ md_link(["a]"],'')], 'Escape inside link (throw ?] away)'],
+
+    ["[a",  :raise,   'Link not closed'],
+    ["[a][",  :raise,   'Ref not closed'],
+
+    # links of the form [text](url)
+    ["\\[a](b)",  ["[a](b)"], 'Links'],
+    ["[a](url)c",  [md_im_link(['a'],'url'),'c'], 'url'],
+    ["[a]( url )c" ],
+    ["[a] (	url )c" ],
+    ["[a] (	url)c" ],
+
+    ["[a](ur:/l/ 'Title')",  [md_im_link(['a'],'ur:/l/','Title')],
+      'url and title'],
+    ["[a] (	ur:/l/ \"Title\")" ],
+    ["[a] (	ur:/l/ \"Title\")" ],
+    ["[a]( ur:/l/ Title)", :raise, "Must quote title" ],
+
+    ["[a](url 'Tit\\\"l\\\\e')", [md_im_link(['a'],'url','Tit"l\\e')],
+      'url and title escaped'],
+    ["[a] (	url \"Tit\\\"l\\\\e\")" ],
+    ["[a] (	url	\"Tit\\\"l\\\\e\"  )" ],
+    ['[a] (	url	"Tit\\"l\\\\e"  )' ],
+    ["[a]()", [md_im_link(['a'],'')], 'No URL is OK'],
+
+    ["[a](\"Title\")", :raise, "No url specified" ],
+    ["[a](url \"Title)", :raise, "Unclosed quotes" ],
+    ["[a](url \"Title\\\")", :raise],
+    ["[a](url \"Title\" ", :raise],
+
+    ["[a](url \'Title\")", :raise, "Mixing is bad" ],
+    ["[a](url \"Title\')"],
+
+    ["[a](/url)", [md_im_link(['a'],'/url')], 'Funny chars in url'],
+    ["[a](#url)", [md_im_link(['a'],'#url')]],
+    ["[a](</script?foo=1&bar=2>)", [md_im_link(['a'],'/script?foo=1&bar=2')]],
+
+
+    # Images
+    ["\\![a](url)",  ['!', md_im_link(['a'],'url') ], 'Escaping images'],
+
+    ["![a](url)",  [md_im_image(['a'],'url')], 'Image no title'],
+    ["![a]( url )" ],
+    ["![a] (	url )" ],
+    ["![a] (	url)" ],
+
+    ["![a](url 'ti\"tle')",  [md_im_image(['a'],'url','ti"tle')], 'Image with title'],
+    ['![a]( url "ti\\"tle")' ],
+
+    ["![a](url", :raise, 'Invalid images'],
+    ["![a( url )" ],
+    ["![a] ('url )" ],
+
+    ["![a][imref]",  [md_image(['a'],'imref')], 'Image with ref'],
+    ["![a][ imref]",  [md_image(['a'],' imref')], 'Image with ref'],
+    ["![a][ imref ]",  [md_image(['a'],' imref ' )], 'Image with ref'],
+    ["![a][\timref\t]",  [md_image(['a'],"\timref\t")], 'Image with ref'],
+
+
+    ['<http://example.com/?foo=1&bar=2>',
+      [md_url('http://example.com/?foo=1&bar=2')], 'Immediate link'],
+    ['a<http://example.com/?foo=1&bar=2>b',
+      ['a',md_url('http://example.com/?foo=1&bar=2'),'b']  ],
+    ['<andrea at censi.org>',
+      [md_email('andrea at censi.org')], 'Email address'],
+    ['<mailto:andrea at censi.org>'],
+    ["Developmen <http://rubyforge.org/projects/maruku/>",
+      ["Developmen ", md_url("http://rubyforge.org/projects/maruku/")]],
+    ["a<!-- -->b", ['a',md_html('<!-- -->'),'b'],
+      'HTML Comment'],
+
+    ["a<!--", :raise, 'Bad HTML Comment'],
+    ["a<!-- ", :raise, 'Bad HTML Comment'],
+
+    ["<?xml <?!--!`3  ?>", [md_xml_instr('xml','<?!--!`3')], 'XML processing instruction'],
+    ["<? <?!--!`3  ?>", [md_xml_instr('','<?!--!`3')] ],
+
+    ["<? ", :raise, 'Bad Server directive'],
+
+    ["a <b", :raise, 'Bad HTML 1'],
+    ["<b",   :raise, 'Bad HTML 2'],
+    ["<b!",  :raise, 'Bad HTML 3'],
+    ['`<div>`, `<table>`, `<pre>`, `<p>`',
+      [md_code('<div>'),', ',md_code('<table>'),', ',
+        md_code('<pre>'),', ',md_code('<p>')],
+      'Multiple HTML tags'],
+
+    ["&andrea", ["&andrea"], 'Parsing of entities'],
+    # no escaping is allowed
+    ["\\&andrea;", ["\\", md_entity("andrea")]],
+    ["l&andrea;", ["l", md_entity('andrea')] ],
+    ["&&andrea;", ["&", md_entity('andrea')] ],
+    ["&123;;&",[md_entity('123'),';',md_entity('amp')]],
+
+    ["a\nThe [syntax page] [s] provides",
+      ['a The ', md_link(['syntax page'],'s'), ' provides'], 'Regression'],
+
+    ['![a](url "ti"tle")', [md_im_image(['a'],'url','ti"tle')],
+      "Image with quotes"],
+    ['![a](url \'ti"tle\')' ],
+
+    ['[bar](/url/ "Title with "quotes" inside")',
+      [md_im_link(["bar"],'/url/', 'Title with "quotes" inside')],
+      "Link with quotes"],
+  ]
+end
+
+EXPECTATIONS.each_cons(2) {|l, r| r[1] ||= l[1]}
+
+describe "The Maruku span parser" do
+  before(:each) do
+    @doc = Maruku.new
+    @doc.attributes[:on_error] = :raise
+  end
+
+  EXPECTATIONS.each do |md, res, comment, pend|
+    if res == :raise
+      it "should raise an error (#{comment}) for \"#{md}\"" do
+        pending if pend
+        lambda {@doc.parse_span(md)}.should raise_error(Maruku::Exception)
+      end
+    else
+      it "should parse \"#{md}\" as #{res.inspect}" do
+        pending if pend
+        @doc.parse_span(md).should == res
+      end
+    end
+  end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..a4f1de4
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,3 @@
+require 'json'
+require 'simplecov'
+SimpleCov.root(File.expand_path(File.dirname(__FILE__) + '/..'))
diff --git a/spec/to_html_utf8_spec.rb b/spec/to_html_utf8_spec.rb
new file mode 100644
index 0000000..e2d1097
--- /dev/null
+++ b/spec/to_html_utf8_spec.rb
@@ -0,0 +1,13 @@
+# encoding: UTF-8
+
+require File.dirname(__FILE__) + '/spec_helper'
+require 'rspec'
+require 'maruku'
+
+describe "Maruku to_html" do
+  # This test used to hang in JRuby!
+  it "can produce HTML for a document that contains non-ASCII characters" do
+    doc = Maruku.new.instance_eval 'md_el(:document,["è"],{},[])'
+    doc.to_html.strip.should == "è"
+  end
+end
diff --git a/tests/bugs/code_in_links.md b/tests/bugs/code_in_links.md
deleted file mode 100644
index 1e1506a..0000000
--- a/tests/bugs/code_in_links.md
+++ /dev/null
@@ -1,101 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-**This bug is now solved**
-
-Previously, a bug would not let you use `code` inside links text.
-
-So this:
-	Use the [`syntax`][syntax]
-produces:
-> Use the [`syntax`][syntax]
-
-And this:
-	Use the `[syntax][syntax]`
-produces:
-> Use the `[syntax][syntax]`
-
-[syntax]: http://gogole.com
-
-
-*** Output of inspect ***
-md_el(:document,[
-	md_par([md_strong(["This bug is now solved"])]),
-	md_par([
-		"Previously, a bug would not let you use ",
-		md_code("code"),
-		" inside links text."
-	]),
-	md_par([
-		"So this: Use the ",
-		md_link([md_code("syntax")],"syntax"),
-		" produces:"
-	]),
-	md_el(:quote,[md_par(["Use the ", md_link([md_code("syntax")],"syntax")])],{},[]),
-	md_par(["And this: Use the ", md_code("[syntax][syntax]"), " produces:"]),
-	md_el(:quote,[md_par(["Use the ", md_code("[syntax][syntax]")])],{},[]),
-	md_ref_def("syntax", "http://gogole.com", {:title=>nil})
-],{},[])
-*** Output of to_html ***
-<p><strong>This bug is now solved</strong></p>
-
-<p>Previously, a bug would not let you use <code>code</code> inside links text.</p>
-
-<p>So this: Use the <a href='http://gogole.com'><code>syntax</code></a> produces:</p>
-
-<blockquote>
-<p>Use the <a href='http://gogole.com'><code>syntax</code></a></p>
-</blockquote>
-
-<p>And this: Use the <code>[syntax][syntax]</code> produces:</p>
-
-<blockquote>
-<p>Use the <code>[syntax][syntax]</code></p>
-</blockquote>
-*** Output of to_latex ***
-\textbf{This bug is now solved}
-
-Previously, a bug would not let you use {\colorbox[rgb]{1.00,0.93,1.00}{\tt code}} inside links text.
-
-So this: Use the \href{http://gogole.com}{{\colorbox[rgb]{1.00,0.93,1.00}{\tt syntax}}} produces:
-
-\begin{quote}%
-Use the \href{http://gogole.com}{{\colorbox[rgb]{1.00,0.93,1.00}{\tt syntax}}}
-
-
-\end{quote}
-And this: Use the {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char91syntax\char93\char91syntax\char93}} produces:
-
-\begin{quote}%
-Use the {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char91syntax\char93\char91syntax\char93}}
-
-
-\end{quote}
-*** Output of to_md ***
-This bug is now solved
-
-Previously, a bug would not let you use
-inside links text.
-
-So this: Use the produces:
-
-Use the
-
-And this: Use the produces:
-
-Use the
-*** Output of to_s ***
-This bug is now solvedPreviously, a bug would not let you use  inside links text.So this: Use the  produces:Use the And this: Use the  produces:Use the
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/bugs/complex_escaping.md b/tests/bugs/complex_escaping.md
deleted file mode 100644
index 5c882c1..0000000
--- a/tests/bugs/complex_escaping.md
+++ /dev/null
@@ -1,38 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-
-
-What do you see here? `\\` it should be two backslashes.
-
-
-*** Output of inspect ***
-md_el(:document,[
-	md_par([
-		"What do you see here? ",
-		md_code("\\\\"),
-		" it should be two backslashes."
-	])
-],{},[])
-*** Output of to_html ***
-<p>What do you see here? <code>\\</code> it should be two backslashes.</p>
-*** Output of to_latex ***
-What do you see here? {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char92\char92}} it should be two backslashes.
-*** Output of to_md ***
-What do you see here? it should be two
-backslashes.
-*** Output of to_s ***
-What do you see here?  it should be two backslashes.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/math/syntax.md b/tests/math/syntax.md
deleted file mode 100644
index d98d124..0000000
--- a/tests/math/syntax.md
+++ /dev/null
@@ -1,46 +0,0 @@
-LaTeX preamble: preamble.tex
-CSS: math.css
-
-Here are some formulas:
-
-*	$\alpha$
-*	$x^{n}+y^{n} \neq z^{n}$
-
-Some inline maths: $\sum_{n=1}^\infty \frac{(-1)^n}{n} = \ln 2$. 
-
-Some display  maths:
-
-\[ \sum_{n=1}^\infty \frac{1}{n} \]
-\[ \sum_{n=1}^\infty \frac{1}{n} \text{ is divergent, but } \lim_{n \to \infty} \sum_{i=1}^n \frac{1}{i} - \ln n \text{ exists.} \]     (a)
-
-Some random AMSTeX symbols - thanks to Robin Snader for adding these:
-
-$$ \beth \Subset \bigtriangleup \smallsmile \bumpeq \ggg \pitchfork $$ 
-
-Note that $\hat g$ , $J$, and $\gamma_1\gamma_2$ all restrict to
-
-$x_1 \overline{x_2} \oplus x_2 \overline{x_1}$ and that this module
-is linear in $x_1$ and $x_2$.
-
-See label \eqref{a}.
-
-$$ \href{#hello}{\alpha+\beta} $$
-
-## Cross references ##
-
-The following are 4 equations, labeled A,B,C,D:
-
-$$ \alpha $$ (A)
-
-\[ 
-	\beta
-\] (B) 
-
-$$ \gamma \label{C} $$
-
-\[ 
-	\delta \label{D}
-\]
-
-You can now refer to (eq:A), (eq:B), \eqref{C}, \eqref{D}.
-
diff --git a/tests/math_usage/document.md b/tests/math_usage/document.md
deleted file mode 100644
index 5ade224..0000000
--- a/tests/math_usage/document.md
+++ /dev/null
@@ -1,13 +0,0 @@
-css: math.css
-
-This is an example document. Inline: $a$, $b$, $q$ and stop.
-
-$$        \int_a^b f(x) dx       $$     (1)
-
-See for example (eq:1).
-
-Equation inline: $  \int_a^b f(x) dx $ and that's it.
-
-
-Spacing: Maruku outputs sizes and alignment for images in `ex`. An `ex` is one `x`:
-x, $\textrm{x}$, $x$ should have the same height. 
diff --git a/tests/others/abbreviations.md b/tests/others/abbreviations.md
deleted file mode 100644
index 06253d1..0000000
--- a/tests/others/abbreviations.md
+++ /dev/null
@@ -1,11 +0,0 @@
-
-The HTML specification is maintained by the W3C.
-
-*[HTML]: Hyper Text Markup Language
-*[W3C]:  World Wide Web Consortium
-
-
-
-Operation Tigra Genesis is going well.
-
-*[Tigra Genesis]:
\ No newline at end of file
diff --git a/tests/others/blank.md b/tests/others/blank.md
deleted file mode 100644
index 78d83a2..0000000
--- a/tests/others/blank.md
+++ /dev/null
@@ -1,4 +0,0 @@
-
-Linea 1
-
-Linea 2
\ No newline at end of file
diff --git a/tests/others/code.md b/tests/others/code.md
deleted file mode 100644
index ce027b7..0000000
--- a/tests/others/code.md
+++ /dev/null
@@ -1,5 +0,0 @@
-Here is an example of AppleScript:
-
-    tell application "Foo"
-        beep
-    end tell
diff --git a/tests/others/code2.md b/tests/others/code2.md
deleted file mode 100644
index eea196e..0000000
--- a/tests/others/code2.md
+++ /dev/null
@@ -1,8 +0,0 @@
-> ## This is a header.
-> 
-> 1.   This is the first list item.
-> 2.   This is the second list item.
-> 
-> Here's some example code:
-> 
->     return shell_exec("echo $input | $markdown_script");
\ No newline at end of file
diff --git a/tests/others/code3.md b/tests/others/code3.md
deleted file mode 100644
index fd3b027..0000000
--- a/tests/others/code3.md
+++ /dev/null
@@ -1,16 +0,0 @@
-
-This is code (4 spaces):
-
-    Code
-This is not code
-    
-    Code
-
-This is code (1 tab):
-
-	Code
-This is not code
-
-	Code
-
-
diff --git a/tests/others/email.md b/tests/others/email.md
deleted file mode 100644
index ed31f08..0000000
--- a/tests/others/email.md
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-This is an email address: <andrea at invalid.it>
-	
\ No newline at end of file
diff --git a/tests/others/entities.md b/tests/others/entities.md
deleted file mode 100644
index 56cb3e4..0000000
--- a/tests/others/entities.md
+++ /dev/null
@@ -1,19 +0,0 @@
-Maruku translates HTML entities to the equivalent in LaTeX:
-
-Entity      | Result
-------------|----------
-`©`    |  ©
-`£`   |  £
-`a b`  |  a b
-`λ`  |  λ
-`—`   |  —
-
-
-Entity-substitution does not happen in code blocks or inline code.
-
-The following should not be translated:
-
-	©
-
-It should read just like this: `©`.
-
diff --git a/tests/others/escaping.md b/tests/others/escaping.md
deleted file mode 100644
index b1b56f8..0000000
--- a/tests/others/escaping.md
+++ /dev/null
@@ -1,16 +0,0 @@
- Hello: ! \! \` \{ \} \[ \] \( \) \# \. \! * \*
-
-
-Ora, *emphasis*, **bold**, * <- due asterischi-> * , un underscore-> _ , _emphasis_,
- incre*dible*e!
-
-
-This is ``Code with an escape:  -> ` <- `` (after)
-
-This is ```Code with a special: -> ` <- ```(after)
-
-`Start ` of paragraph
-
-End of `paragraph `
-
-Exactly one space: `   ` and also here: ``   ``
\ No newline at end of file
diff --git a/tests/others/extra_dl.md b/tests/others/extra_dl.md
deleted file mode 100644
index f2747b0..0000000
--- a/tests/others/extra_dl.md
+++ /dev/null
@@ -1,101 +0,0 @@
-CSS: style.css
-
-
-Apple
-:   Pomaceous fruit of plants of the genus Malus in 
-    the family Rosaceae.
-
-Orange
-:   The fruit of an evergreen tree of the genus Citrus.
-
-***
-
-Apple
-:   Pomaceous fruit of plants of the genus Malus in 
-the family Rosaceae.
-
-Orange
-:   The fruit of an evergreen tree of the genus Citrus.
-
-
-***
-
-Apple
-:   Pomaceous fruit of plants of the genus Malus in 
-    the family Rosaceae.
-:   An american computer company.
-
-Orange
-:   The fruit of an evergreen tree of the genus Citrus.
-
-***
-
-Term 1
-Term 2
-:   Definition a
-
-Term 3
-:   Definition b
-
-***
-
-
-Term 1
-Term 2
-Term 2a
-Term 2b
-:   Definition a
-
-Term 3
-:   Definition b
-
-***
-
-Apple
-
-:   Pomaceous fruit of plants of the genus Malus in 
-    the family Rosaceae.
-
-Orange
-
-:    The fruit of an evergreen tree of the genus Citrus.
-
-***
-
-Term 1
-
-:   This is a definition with two paragraphs. Lorem ipsum 
-    dolor sit amet, consectetuer adipiscing elit. Aliquam 
-    hendrerit mi posuere lectus.
-
-    Vestibulum enim wisi, viverra nec, fringilla in, laoreet
-    vitae, risus.
-
-:   Second definition for term 1, also wrapped in a paragraph
-    because of the blank line preceding it.
-
-Term 2
-
-:   This definition has a code block, a blockquote and a list.
-
-        code block.
-
-    > block quote
-    > on two lines.
-
-    1.  first list item
-    2.  second list item
-
-***
-
-Term 1
-Term 2
-Term 2a
-Term 2b
-:   Definition a
-
-This is a paragraph
-
-This is a term
-
-: definition
\ No newline at end of file
diff --git a/tests/others/extra_header_id.md b/tests/others/extra_header_id.md
deleted file mode 100644
index 05c1afd..0000000
--- a/tests/others/extra_header_id.md
+++ /dev/null
@@ -1,13 +0,0 @@
-Header 1            {#header1}
-========
-
-Header 2            {#header2}
---------
-
-### Header 3 ###      {#header3}
-
-Then you can create links to different parts of the same document like this:
-
-[Link back to header 1](#header1),
-[Link back to header 2](#header2),
-[Link back to header 3](#header3)
diff --git a/tests/others/extra_table1.md b/tests/others/extra_table1.md
deleted file mode 100644
index c094f77..0000000
--- a/tests/others/extra_table1.md
+++ /dev/null
@@ -1,40 +0,0 @@
-CSS: style.css
-
-First Header  | Second Header
-------------- | -------------
-Content Cell  | Content Cell
-Content Cell  | Content Cell
-
-***
-
-| Item      | Value |
-| --------- | -----:|
-| Computer  | $1600 |
-| Phone     |   $12 |
-| Pipe      |    $1 |
-
-***
-
-| Function name | Description                    |
-| ------------- | ------------------------------ |
-| `help()`      | Display the help window.       |
-| `destroy()`   | **Destroy your computer!**     |
-
-
-***
-
-| Very long long head  | 
-| :------------        | 
-| left                 | 
-
-***
-
-| Very long long head  | 
-| -------------------: | 
-| right                |
-
-***
-
-| Very long long head  | 
-| :------------------: | 
-| center               |
\ No newline at end of file
diff --git a/tests/others/footnotes.md b/tests/others/footnotes.md
deleted file mode 100644
index 5f8c9e7..0000000
--- a/tests/others/footnotes.md
+++ /dev/null
@@ -1,17 +0,0 @@
-That's some text with a footnote [^b] and another [^c] and another [^a].
-
-[^a]: And that's the footnote.
-
-    That's the second paragraph of the footnote.
-
-
-[^b]: And that's the footnote.
-This is second sentence (same paragraph).
-
-[^c]:
-    This is the very long one.
-
-    That's the second paragraph.
-
-
-This is not a footnote.
\ No newline at end of file
diff --git a/tests/others/headers.md b/tests/others/headers.md
deleted file mode 100644
index 5eef682..0000000
--- a/tests/others/headers.md
+++ /dev/null
@@ -1,10 +0,0 @@
-A title with *emphasis*
-=======================
-
-A title with *emphasis*
------------------------
-
-
-#### A title with *emphasis* ####
-
-
diff --git a/tests/others/hrule.md b/tests/others/hrule.md
deleted file mode 100644
index 8705b9e..0000000
--- a/tests/others/hrule.md
+++ /dev/null
@@ -1,10 +0,0 @@
-* * *
-
-***
-
-*****
-
-- - -
-
----------------------------------------
-
diff --git a/tests/others/images.md b/tests/others/images.md
deleted file mode 100644
index cbfd31b..0000000
--- a/tests/others/images.md
+++ /dev/null
@@ -1,20 +0,0 @@
-
-This page does not utilizes ![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss)
-
-
-Please mouseover to see the title: ![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss "Title ok!")
-
-Please mouseover to see the title: ![Cascading Style Sheets](http://jigsaw.w3.org/css-validator/images/vcss 'Title ok!')
-
-
-I'll say it one more time: this page does not use ![Cascading Style Sheets] [css]
-
-This is double size: ![Cascading Style Sheets] [css2]
-
-
-
-[css]: http://jigsaw.w3.org/css-validator/images/vcss "Optional title attribute"
-
-[css2]: http://jigsaw.w3.org/css-validator/images/vcss "Optional title attribute" class=external
-   style="border:0;width:188px;height:131px"
-
diff --git a/tests/others/inline_html.md b/tests/others/inline_html.md
deleted file mode 100644
index a5a68a1..0000000
--- a/tests/others/inline_html.md
+++ /dev/null
@@ -1,42 +0,0 @@
-CSS: style.css
-
-Input:
-     <em>Emphasis</em>
-Result: <em>Emphasis</em>
-
-Input:
-	<img src="http://jigsaw.w3.org/css-validator/images/vcss"/>
-Result on span: <img src="http://jigsaw.w3.org/css-validator/images/vcss"/>
-
-Result alone: 
-
-<img src="http://jigsaw.w3.org/css-validator/images/vcss"/>
-
-Without closing:
-
-<img src="http://jigsaw.w3.org/css-validator/images/vcss">
-
-<div markdown="1">
-	This is *true* markdown text (paragraph)
-
-	<p markdown="1">
-		This is *true* markdown text (no paragraph)
-	</p>
-</div>
-
-<table>
-<tr>
-<td markdown="1">This is *true* markdown text. (no par)</td>
-<td markdown="block">This is *true* markdown text. (par)</td>
-</tr>
-</table>
-
-
-The following is invalid HTML, and will generate an error:
-
-<table>
-<td markdown="1">This is *true* markdown text. (no par)</td>
-<td markdown="block">This is *true* markdown text. (par)</td>
-</tr>
-</table>
-
diff --git a/tests/others/links.md b/tests/others/links.md
deleted file mode 100644
index 9c6eac3..0000000
--- a/tests/others/links.md
+++ /dev/null
@@ -1,38 +0,0 @@
-
-Search on [Google][]
-
-Search on [Google] []
-
-Search on [Google] [google]
-
-Search on [Google] [Google]
-
-Search on [Google images][]
-
-Search on [Google images][ 	GoOgle_search ]
-
-Inline: [Google images](http://google.com)
-
-Inline with title: [Google images](http://google.com "Title")
-
-Inline with title: [Google images]( http://google.com  "Title" )
-
-
-Search on <http://www.gogole.com> or <http://Here.com> or ask <mailto:bill at google.com>
-or you might ask bill at google.com.
-
-If all else fails, ask [Google](http://www.google.com)
-	
-[google]: http://www.google.com
-
-[google2]: http://www.google.com 'Single quotes'
-
-[google3]: http://www.google.com "Double quotes"
-
-[google4]: http://www.google.com (Parenthesis)
-
-[Google Search]: 
- http://www.google.com "Google search"
-
-[Google Images]: 
- http://images.google.com  (Google images)
\ No newline at end of file
diff --git a/tests/others/list1.md b/tests/others/list1.md
deleted file mode 100644
index 68c79a9..0000000
--- a/tests/others/list1.md
+++ /dev/null
@@ -1,4 +0,0 @@
-*   A list item with a blockquote:
-
-    > This is a blockquote
-    > inside a list item.
diff --git a/tests/others/list2.md b/tests/others/list2.md
deleted file mode 100644
index db67519..0000000
--- a/tests/others/list2.md
+++ /dev/null
@@ -1,5 +0,0 @@
-*   This is a list item with two paragraphs.
-
-    This is the second paragraph in the list item. You're
-only required to indent the first line. Lorem ipsum dolor
-sit amet, consectetuer adipiscing elit.
diff --git a/tests/others/list3.md b/tests/others/list3.md
deleted file mode 100644
index 8cec256..0000000
--- a/tests/others/list3.md
+++ /dev/null
@@ -1,8 +0,0 @@
-*   A list item with a blockquote:
-
-    > This is a blockquote
-    > inside a list item.
-
-*   A list item with a code block:
-
-        <code goes here>
\ No newline at end of file
diff --git a/tests/others/lists.md b/tests/others/lists.md
deleted file mode 100644
index 9cfdde2..0000000
--- a/tests/others/lists.md
+++ /dev/null
@@ -1,32 +0,0 @@
-*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
-    Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
-    viverra nec, fringilla in, laoreet vitae, risus.
-*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-    Suspendisse id sem consectetuer libero luctus adipiscing.
-*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-Suspendisse id sem consectetuer libero luctus adipiscing.
- *  Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-Suspendisse id sem consectetuer libero luctus adipiscing.
- *  Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
- Suspendisse id sem consectetuer libero luctus adipiscing.
-
-Ancora
-
-*   This is a list item with two paragraphs. Lorem ipsum dolor
-    sit amet, consectetuer adipiscing elit. Aliquam hendrerit
-    mi posuere lectus.
-
-    ATTENZIONE!
-
-*  Suspendisse id sem consectetuer libero luctus adipiscing.
-
-
-Ancora
-
-*   This is a list item with two paragraphs.
-
-    This is the second paragraph in the list item. You're
-only required to indent the first line. Lorem ipsum dolor
-sit amet, consectetuer adipiscing elit.
-
-*   Another item in the same list.
\ No newline at end of file
diff --git a/tests/others/lists_after_paragraph.md b/tests/others/lists_after_paragraph.md
deleted file mode 100644
index 441d39c..0000000
--- a/tests/others/lists_after_paragraph.md
+++ /dev/null
@@ -1,44 +0,0 @@
-Paragraph, list with no space:
-* ciao
-
-Paragraph, list with 1 space:
- * ciao
-
-Paragraph, list with 3 space:
-   * ciao
-
-Paragraph, list with 4 spaces:
-    * ciao
-
-Paragraph, list with 1 tab:
-	* ciao
-
-Paragraph (1 space after), list with no space: 
-* ciao
-
-Paragraph (2 spaces after), list with no space:  
-* ciao
-
-Paragraph (3 spaces after), list with no space:   
-* ciao
-
-Paragraph with block quote:
-> Quoted
-
-Paragraph with header:
-### header ###
-
-Paragraph with header on two lines:
-header
-------
-
-
-Paragraph with html after
-<div></div>
-
-Paragraph with html after, indented:
-     <em>Emphasis</em>
-
-Paragraph with html after, indented: <em>Emphasis</em> *tralla* <em>Emph</em>
-
-Paragraph with html after, indented: <em>Emphasis *tralla* Emph</em>
diff --git a/tests/others/lists_ol.md b/tests/others/lists_ol.md
deleted file mode 100644
index 3e5d699..0000000
--- a/tests/others/lists_ol.md
+++ /dev/null
@@ -1,39 +0,0 @@
-1.   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
-    Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
-    viverra nec, fringilla in, laoreet vitae, risus.
- 2.   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-    Suspendisse id sem consectetuer libero luctus adipiscing.
-3.   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-Suspendisse id sem consectetuer libero luctus adipiscing.
- 3.  Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-Suspendisse id sem consectetuer libero luctus adipiscing.
- 4.  Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
- Suspendisse id sem consectetuer libero luctus adipiscing.
-
-Ancora
-
-1.  This is a list item with two paragraphs. Lorem ipsum dolor
-    sit amet, consectetuer adipiscing elit. Aliquam hendrerit
-    mi posuere lectus.
-
-    ATTENZIONE!
-
-    - Uno
-    - Due
-      1. tre
-      1. tre
-      1. tre
-    - Due
-
-2.  Suspendisse id sem consectetuer libero luctus adipiscing.
-
-
-Ancora
-
-*   This is a list item with two paragraphs.
-
-    This is the second paragraph in the list item. You're
-only required to indent the first line. Lorem ipsum dolor
-sit amet, consectetuer adipiscing elit.
-
-*   Another item in the same list.
\ No newline at end of file
diff --git a/tests/others/misc_sw.md b/tests/others/misc_sw.md
deleted file mode 100644
index 2ba51cc..0000000
--- a/tests/others/misc_sw.md
+++ /dev/null
@@ -1,105 +0,0 @@
-Subject: Software not painful to use
-Subject_short: painless software
-Topic: /misc/coolsw
-Archive: no
-Date: Nov 20 2006
-Order: -9.5
-inMenu: true
-
-
-### General ###
-
-* *Operating System* : [Mac OS X][switch]: heaven, after the purgatory of Linux 
-  and the hell of Windows.
-* *Browser*: [Firefox][firefox]. On a Mac, [Camino][camino].
-* *Email*: [GMail][gmail], "search, don't sort" really works.
-* *Text Editor*: [TextMate][textmate], you have to buy it, but it's worth every
-  penny. There are rumours that it's been converting (recovering) Emacs
-  users (addicts). Unfortunately, it's Mac only. An alternative is
-  [jedit][jedit] (GPL, Java).
-
-### Development ###
-
-* *Build system*: [cmake][cmake], throw the [autotools][autotools] away.
-* *Source code control system*: ditch CVS for [subversion][subversion].
-* *Project management*: [Trac][trac] tracks everything.
-* *Scripting language*: [Ruby][ruby] is Japanese pragmatism (and has a [poignant][poignant] guide). 
-   Python, you say? Python is too academic and snob:
-
-      $ python       
-      Python 2.4.1 (\#1, Jun  4 2005, 00:54:33) 
-      Type "help", "copyright", "credits" or "license" for more information.
-      >>> exit
-      'Use Ctrl-D (i.e. EOF) to exit.'
-      >>> quit
-      'Use Ctrl-D (i.e. EOF) to exit.'
-
-* *Java IDE*: [JBuilder][jbuilder] is great software and has a free version (IMHO better than Eclipse). Java
- is not a pain anymore since it gained [generics][java-generics] and got opensourced.
-* *Mark-up language*: HTML is so 2001, why don't you take at look at [Markdown][markdown]? [Look at the source of this page](data/misc_markdown.png).
-* *C++ libraries*: 
-    * [QT][qt] for GUIs.
-    * [GSL][gsl] for math.
-    * [Magick++][magick] for manipulating images.
-    * [Cairo][cairo] for creating PDFs.
-    * [Boost][boost] for just about everything else.
-
-
-### Research ###
-
-* *Writing papers*: [LaTeX][latex]
-* *Writing papers & enjoying the process*: [LyX][lyx]
-* *Handsome figures in your papers*: [xfig][xfig] or, better, [jfig][jfig].
-* *The occasional presentation with many graphical content*: 
-  [OpenOffice Impress][impress] (using the [OOOlatex plugin][ooolatex]); 
-  the alternative is PowerPoint with the [TexPoint][texpoint] plugin.
-* *Managing BibTeX*: [jabref][jabref]: multi-platform, for all your bibtex needs.
-* *IEEExplore and BibTeX*: convert citations using [BibConverter][bibconverter].
-
-### Cool websites ###
-
-* *Best site in the wwworld*: [Wikipedia][wikipedia]
-* [Mutopia][mutopia] for sheet music; [the Gutenberg Project][gutenberg] for books; [LiberLiber][liberliber] for books in italian.
-* *Blogs*: [Bloglines][bloglines]
-* *Sharing photos*: [flickr][flickr] exposes an API you can use.
-
-
-[firefox]:   http://getfirefox.com/
-[gmail]:     http://gmail.com/
-[bloglines]: http://bloglines.com/
-[wikipedia]: http://en.wikipedia.org/
-[ruby]:      http://www.ruby-lang.org/
-[poignant]:  http://poignantguide.net/ruby/
-[webgen]:    http://webgen.rubyforge.org/
-[markdown]:  http://daringfireball.net/projects/markdown/
-[latex]:     http://en.wikipedia.org/wiki/LaTeX
-[lyx]:       http://www.lyx.org
-[impress]:   http://www.openoffice.org/product/impress.html
-[ooolatex]:  http://ooolatex.sourceforge.net/
-[texpoint]:  http://texpoint.necula.org/
-[jabref]:    http://jabref.sourceforge.net/
-[camino]:    http://www.caminobrowser.org/
-[switch]:    http://www.apple.com/getamac/
-[textmate]:  http://www.apple.com/getamac/
-[cmake]:     http://www.cmake.org/
-[xfig]:      http://www.xfig.org/
-[jfig]:         http://tams-www.informatik.uni-hamburg.de/applets/jfig/
-[subversion]:   http://subversion.tigris.org
-[jbuilder]:     http://www.borland.com/us/products/jbuilder/index.html
-[flickr]:       http://www.flickr.com/
-[myflickr]:     http://www.flickr.com/photos/censi
-[bibconverter]: http://www.bibconverter.net/ieeexplore/
-[autotools]:    http://sources.redhat.com/autobook/
-[jedit]:        http://www.jedit.org/
-[qt]:           http://www.trolltech.no/
-[gsl]:          http://www.gnu.org/software/gsl/
-[magick]:       http://www.imagemagick.org/Magick++/
-[cairo]:        http://cairographics.org/
-[boost]:        http://www.boost.org/
-[markdown]:     http://en.wikipedia.org/wiki/Markdown
-[trac]:         http://trac.edgewall.org/
-[mutopia]:      http://www.mutopiaproject.org/
-[liberliber]:   http://www.liberliber.it/
-[gutenberg]:    http://www.gutenberg.org/
-[java-generics]: http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html
-
diff --git a/tests/others/one.md b/tests/others/one.md
deleted file mode 100644
index 7452380..0000000
--- a/tests/others/one.md
+++ /dev/null
@@ -1 +0,0 @@
-One line
\ No newline at end of file
diff --git a/tests/others/paragraphs.md b/tests/others/paragraphs.md
deleted file mode 100644
index 2fc20f5..0000000
--- a/tests/others/paragraphs.md
+++ /dev/null
@@ -1,13 +0,0 @@
-Paragraph 1
-
-Paragraph 2
-
-
-Paragraph 3
-Paragraph 4
-Paragraph Br->  
-Paragraph 5
-
-
-
-Escaping: & { } [ ] ! 
diff --git a/tests/others/sss06.md b/tests/others/sss06.md
deleted file mode 100644
index fbe8b4f..0000000
--- a/tests/others/sss06.md
+++ /dev/null
@@ -1,352 +0,0 @@
-Category: sss06
-Date: Sep 10 2006
-From: "Andrea Censi" <andrea.censi at dis.uniroma1.it>
-Subject: A report about Oxford and the 2006 SLAM Summer School
-Encoding: BlueCloth FlickrHTML
-format: bluecloth>
-inMenu: true
-
-Let me quote the words of a renowned Oxford scholar:
-
-> "Life is too important to be taken seriously."
-
-If you do not wholeheartedly agree with this statement,
-please stop reading this.
-
-----------------------
-
-I stayed three weeks in Oxford: one week for the SLAM school and,
-before that, two weeks for an English course. You might ask: why?
-A very good question indeed - "Why I am not on a sunny beach?" -
-I kept asking myself as I walked down the misty alleys of the old town,
-wearing a scarf on August, 16th, and realizing that - maybe - I would not
-need the three pairs of shorts and the swimsuit I had brought.
-
-
-Summary:
-
-1. The Queen's English
-2. The Harry Potter experience
-3. Parsnip, Marmite and the tea conspiracy
-4. The Summer School
-5. Minor open issues in SLAM  
-
-> Appendix: How to offend seven nationalities at once
-
-`I`. The Queen's English
-----------------------
- 
-It turns out that a course of English at an advanced level is mostly
-about vocabulary and idioms: by the end of the first week I knew seven
-different ways to address a "promiscuous" woman, and I can tell which ones
-are applicable to American and which to British English. It remains to be
-seen how this will benefit my academic writing.
-
-It was a lot of fun to learn the differences (or, as the teacher put it,
-"to purify my English after years of prolonged unhealthy exposure to American
-media"), which are not only linguistic, but above all in attitude and
-social norms.
-For example, in the US the first question that people ask you is
-"What do you do?" (meaning: "How much do you earn?"), while in England such
-a question would be felt as unnecessary direct and impolite. 
-As a rule,
-it is compulsory to exchange comments about the weather, and there is a lot
-of specialized vocabulary for this; the following table might prove handy
-to understand your acquaintance:
-
-- "It's a lovely day!" = "It doesn't rain"
-- "It's a nice day!" = "It doesn't rain heavily"
-- "What a wonderful day!"="This morning, at 10:13, I caught a glimpse of the sun"
-
-(the correct answer to any of these is "isn't it?")
-
-`II`. The Harry Potter experience
--------------------------
-
-  flickr: http://www.flickr.com/photos/censi/232006603/
-
-During my three-week stay I tried my best to immerse myself in the English
-atmosphere.
-
-I went to a place called Oxford Story [3], where we paid £7 to go through a
-painfully slow indoor ride, sat on a mobile school-desk in the dark for 25
-minutes. It is the claustrophobic equivalent of the American Epcot center in
-Disney World.
-
-At Epcot, I learned that the final goal of all the scientific progress in the
-last three millennia was to let Walt Disney broadcast Snow White using
-Siemens equipment (Siemens sponsored the ride).
-In Oxford, I learned that the glorious University is the repository of all
-human knowledge, and that the English understatement is a legend. At the end of
-the ride, I was amazed that in Italy I had managed to learn to read and write.
-
-  flickr: http://www.flickr.com/photos/censi/232023681/
-
-Still, one thing the ride did not explain is how the well-educated,
-smart elite students of Oxford can possibly find rowing fun --
-(probably it IS fun, compared to cricket).
-
-  flickr: http://www.flickr.com/photos/censi/232529032/
-
-I went to a candle-light baroque concert in the Exeter college chapel.
-The ensemble was 75% Asian, all Oxford researchers, and we were given
-a twenty minute speech about the effort they put in the historical
-research of this obscure composer, that they had a microfilm of the original
-manuscript delivered from a German library, that the viola would be played
-in the original style, blah blah blah. Only in Oxford!
-
-  flickr: http://www.flickr.com/photos/censi/232031895/
-
-I read "The Hobbit" (Tolkien was a fellow of Exeter college) - I discovered
-that the only two peoples in the known and invented universes to have
-the concept of a "second breakfast" are Hobbits and Italians.
-
-
-I watched a performance of MacBeth at an open-air theatre.
-I couldn't understand but one sentence, which is worth mentioning:
-"Alcohol provokes the desire, but it takes away the performance"
-
-Regarding alcohol, England is one of the places where you can't drink if you
-are under 21 (in Italy, at 18 you have decided to quit).
-Young people have their ID checked at the entrance of pubs and in liquor
-stores: that's only a minor annoyance, as they just need to wait outside
-the store for the first Spanish guy passing by that will buy the wine for them
-(and be compensated with just the change - did you keep the penny, Felix?).
-
-Anyway the guys at the door use the ID checking mostly as a form of flattery:
-"You are 32? I thought you were 20!" is probably the best pick-up line that
-the English can come up with.
-
-The other characteristic thing is that in English pubs there is no table
-service: you have to walk to the bar and ask by yourself. The first time can
-be confusing: and you can spend quite some time waiting at the table whining
-about the "poor service".
-
-`III`. Parsnip, Marmite & the tea conspiracy 
----------------------------------------------
-
-During the first week I was a guest of a lovely 79-year-old lady.
-Working at the University, she made a point of speaking very posh English.
-And she made a point of cooking traditional English food.
-The typical English dish is some meat with two vegetables aside.
-For the vegetables, pick any two in {parsnip, carrot, potato}.
-
-Don't look in your dictionary for a translation of "parsnip" as probably
-there isn't one. The lady would tell me that in the next-to-last century,
-this famous professor spent years raising the finest crossbreed of Parsnip as
-to finally obtain what is best described as a big white carrot
-with no taste whatsoever [4].
-
-Nevertheless, the many regional variants give spectacular variety to the
-English cuisine: the two vegetables can be boiled, fried, baked, microwaved,
-or roasted. There exist also exotic twists, in which the vegetables are put
-on top of the meat, or underneath, or even inside.
-In important occasions, the recipes stay the same but gain a French name.
-
-
-   flickr: http://www.flickr.com/photos/censi/232526897/
-
-
-I tried a thing called Marmite, which the teacher sold to me as "the British
-answer to Nutella". It has the aspect and consistency of engine grease, and,
-as far as I know, also the taste is similar (I've never tasted the grease,
-but next time, presented with choice, I'd give it a go).
-
-The austerity of English food can be explained by the pitiless weather; but
-how can you explain Marmite, if not with alimentary masochism?
-
-But... there's one thing that is much better in England: tea. Wherever I tried
-it (at the old lady's, at tearooms, at coffee breaks) it was sooo delicious.
-In Italy we don't get the real thing. Why is that? Is this some sort of
-conspiracy orchestrated by the Italian coffee producers? And is it the
-tea cartello which does not allow good coffee to be imported in England?
-
-`IV`. The Summer School
----------------------
-
-If you go for a career in research, in general you don't get much money,
-or fame, and you don't get to rescue the princess either.
-The two benefits that you do get are: playing with very expensive toys
-and the occasional trip in which you meet all sort of people.
-
-And when you talk with them, it's sort of strange to realize that your
-interlocutor is one of the 5 people - worldwide - that actually care about your
-research theme, and yet the things you have in common end there, as he has
-different culture, race, religion, and while you two happen to agree that Lie
-brackets are an indispensable tool to characterize the propagation of errors
-on the Euclidean group, you have very different answers to the important
-questions about life, the universe and everything. (In these cases I have
-anecdotal proof that it is much better to stick to research talk, and to
-avoid at all costs the kind of jokes that you can find in the Appendix).
-
-Instead, at this particular school, I would say that the European character was
-clearly perceived, and I enjoyed it -- but whether England is in Europe is a
-delicate matter.
-
-
-Here are some impressions of the people.
-
- * Juan Domingo Tardos (aka Mingo) is the funniest of the bunch, the man you
-   want to go partying with.
-   
-   He taught us two deep truths about SLAM and life:
-   1. The size of your banana matters.
-   2. Never under-estimate the size of your lemons.
-   
-   I thought: wow, I want to write a paper with "banana" in the title - finally
-   some inspiration from the school! I already had big projects for Fig. 1,2
-   and a full-page Fig. 3, but after a little googling I found:
-   "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire"[5]
-   "Dealing with large bananas" [6].
-   I gave up: I cannot beat this last one. And the existence of [6] proves
-   once again that SLAM is a solved problem.
-
- * Paul Newman, the organizer, told us, more than once, that the future of SLAM
-   is in long term operation if we want the systems to be reliable.
-   (Personally, I disagree: I think that it is possible to build anything at
-   the desired level of reliability, given reasonable funding, time, and
-   an appropriate number of German engineers)
-
- * One of the lessons learned in the school is that almost everything has
-   already been done by someone else.
-   More specifically, most of the things have already been done by
-   Durrant-Whyte some twenty years ago, when men were men, CS was electrical
-   engineering, master students knew calculus, and Kalman filters ran
-   free in the wild lands of Australia.
-
- * Frank Dellaert is a jolly chap as well, and he does interesting things with
-   graphs. As he introduced three different formalisms in the first
-   three slides, I regretted not to have put more CS in my curriculum, then
-   shut my eyes. Interestingly, at summer schools and conferences, if you close
-   your eyes people assume that you are very smart and that you are thinking
-   about some new impressive algorithm -- I was just dreaming of a sunny beach.
-
- * Henrik Christensen has implemented SLAM on the cleaning robot for $45
-   in sensors and electronics. It puts things in perspective, especially
-   if you consider that I paid  £16 for a one-hour coach trip from Heathrow
-   to Oxford.
-
- * Andy Davison is a wonderful person, he tutored the practicals with
-   infinite patience. Never did I meet such a knowledgeable, affable,
-   and humble person. (Probably he is the kind of person that some day will
-   show up at work with automatic guns)
-
- * Wolfram Burgard - he wins my "best robot" award for the photo of our
-   beloved Albert [7].
-
- * Dieter Fox wins "most nostalgic slide from the 90s": and every time we feel
-   the same emotion as the first time.
-
- * Kurt Konolige reminded me why I bought a Mac.
-
- * Simon Lacroix - Once we sat at the same table during lunch. While he
-   talked with Dellaert, he would send me alarmed glances, the kind of glances
-   that you would reserve to a relative returning from death. I wanted
-   to ask him why, but then I decided I'd better not to (was I so wasted
-   from the night before?).
-
- * Simon Julier -- he seems very smart, but he lost me between slide #3 and #4.
-   I started to be seasick from all those covariance matrices -
-   so I muttered to my neighbours: "I wonder whether it still holds in
-   higher-dimensional spaces...", then I closed my eyes and was back again on
-   the sunny beach.
-
- * But all in all, the most interesting presentation was the magical show
-   that Davide Scaramuzza (who at daytime pretends to work at ETHZ) gave to a
-   selected audience after the banquet ([8]).
-   It was another confirmation that all the time spent in front of a monitor is,
-   in fact, wasted, and all of us should have studied card tricks instead:
-   you have NO IDEA of how a girl's face brightens up and her eyes expand when
-   she watches a magician.
-
-`V`. Other minor issues in SLAM 
---------------------------------
-
-We all know that the most important open problem in SLAM is that there are
-not enough women doing research in the area and coming at summer schools.
-As for the other minor issues, this is the result of asking
-"What is the future of SLAM?" to a random sampling of the participants.
-(the list does not include answers given after 10:00 PM)
-
- - For 30% of the respondents, SLAM is a solved problem, and we just need some
-   German engineers to work out the details of the implementations.
- - Long term operation: make filters that reconsider their decisions at a
-   a later time (so not delaying decisions, but explicitly reconsider).
- - Make it robust for real applications: or, your method should work in more
-   than one experiment and possibly also outside of your lab.
- - Put more knowledge in SLAM about the environment. Teach your
-   filter what is a tree, a road, a mirror so that it can make smarter
-   decisions.
- - Active SLAM and SLAM-guided exploration (once we figure out good acronyms).
- - Some boring work is to be done for taking into account linearization errors
-   in the already existing results about consistency, sparsity, etc.
- - "Where can I get some real coffee?" (2 people)
- - Methods and representations for real sensor fusion (laser, camera, etc).
- - Do robust stuff with a single camera. Omnidirectional cameras are cool.
-   Mix different techniques at different time-scales: visual odometry between
-   frames, then stable features, then databases of places to close the loop
-   (or don't close the loop at all).
-
-Appendix. How to offend seven nationalities at once
---------------------------------------------------
-
-In Oxford I learned the ultimate rude stereotypical joke -- I think it's
-worth sharing.
-
-> **Heaven & Hell**
->
-> *In Heaven*: the policemen are British, mechanics are German, chefs are French,
-> wives are Japanese, neighbours are Dutch, lovers are Italian,
-> and the Swiss organize it all.
->
-> *In Hell*: the policemen are German, mechanics are French, chefs are British,
-> neighbours are Japanese, wives are Dutch, lovers are Swiss,
-> and the Italians organize it all.
-
-For related work, see for example [9], [10].
-
-
-And here's the research version:
-
-> **The BEST international research project**
-> 
-> - The French do the overall math analysis,
-> - a Chinese refines a ten-line proof of the main Theorem,
-> - the Germans design the implementation,
-> - Japanese undergrads do the actual work,
-> - the British write the paper,
-> - an American gives the presentation,
-> - the Spanish organize the social events,
-> - and the Italians organize the banquet.
-> 
-> **The WORST international research project**
-> 
-> - The Germans do the overall math analysis,
-> - an American PhD student spends 10 CPU year on his department's 48-node
-> cluster and proves with a Monte Carlo simulation in Matlab that
-> Theorem 1 indeed holds for some values of the parameters,
-> - the French design the implementation,
-> - one Spanish undergrad does the actual work,
-> - the Italians write the papers,
-> - a Chinese gives the presentation,
-> - the Japanese organize the social events,
-> - and the British organize the banquet.
-
-`:-)`
-
-  Flickr: <http://www.flickr.com/photos/censi/232003838>
-
-References
-----------
-
-\[1\]   [http://www.spellingsociety.org/news/media/poems.php](http://www.spellingsociety.org/news/media/poems.php)  
-\[2\] dde [http://www.flickr.com/photos/censi/236722418/](http://www.flickr.com/photos/censi/236722418/)  
-\[3\]  [http://www.oxfordstory.co.uk](http://www.oxfordstory.co.uk)  
-\[4\]   [http://www.botanical.com/botanical/mgmh/p/parsni12.html](http://www.botanical.com/botanical/mgmh/p/parsni12.html  )  
-\[5\]  E. Meijer, M. Fokkinga, R. Paterson. "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire" (1991)  
- [http://citeseer.ist.psu.edu/meijer91functional.html](http://citeseer.ist.psu.edu/meijer91functional.html)  
-\[6\]  R. Lammel, J. Visser, J. Kort. "Dealing with large bananas" (2000) <http://citeseer.ist.psu.edu/lammel00dealing.html>  
-\[7\]  [http://www.informatik.uni-freiburg.de/~burgard/](http://citeseer.ist.psu.edu/lammel00dealing.html)  
-\[8\]  [http://asl.epfl.ch/~scaramuz/cabaret/cabaret.wmv](http://asl.epfl.ch/~scaramuz/cabaret/cabaret.wmv)  
-\[9\]  [http://www.anth.uconn.edu/faculty/boster/cultvar/euweb/](http://www.anth.uconn.edu/faculty/boster/cultvar/euweb/)  
-\[10\]  [http://www.infonegocio.com/xeron/bruno/italy.html](http://www.infonegocio.com/xeron/bruno/italy.html)  
diff --git a/tests/others/test.md b/tests/others/test.md
deleted file mode 100644
index 96ecb93..0000000
--- a/tests/others/test.md
+++ /dev/null
@@ -1,4 +0,0 @@
-
-           $ python       
-
-
diff --git a/tests/s5/s5profiling.md b/tests/s5/s5profiling.md
deleted file mode 100644
index fbf6caf..0000000
--- a/tests/s5/s5profiling.md
+++ /dev/null
@@ -1,48 +0,0 @@
-subtitle: news
-author: Andrea Censi
-company: Università La Sapienza
-css: math.css
-
-RDK news
-========
-
-Profiling
----------------------------------------------------------
-
-1. `ragent2` writes profiling information on a pipe.
-2. `rdk-profiler` reads the pipe and creates graphs in HTML+Javascript.
-3. The user reads the data on a browser. 
-
-Things logged
------------------------------------------------------------
-
-	17288397 1730000 0 16384 END pantiltClient 
-	17288439 1730000 0 16384 START pantiltClient 
-	17288564 1730000 0 16384 LOCK pantiltClient:tilt 
-	17288622 1730000 0 16384 UNLOCK pantiltClient:tilt
-
-* `START/END`: how much does it take to ...?
-
-Footnotes 1/2
----------------------------------------------------
-
-You can use footnotes [^1]
-
-[^1]: And they work.
-
-Footnotes 2/2
----------------------------------------------------
-
-Each footnote on its page [^2]
-
-[^2]: alone.
-
-And now: math!
----------------------------------------------------
-
-Consider, for example the group $\int_{a}^{b} x^{a} db$ of 
-
-\[         \alpha_{\beta}^{\gamma} \]
-
-Unfortunately S5 and MathML are mutually exclusive. 
-See <http://meyerweb.com/eric/thoughts/category/tech/s5/> for explanations.
\ No newline at end of file
diff --git a/tests/unittest/bug_def.md b/tests/unittest/bug_def.md
deleted file mode 100644
index 642c292..0000000
--- a/tests/unittest/bug_def.md
+++ /dev/null
@@ -1,28 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-[test][]:
-
-*** Output of inspect ***
-md_el(:document,[md_par([md_link(["test"],"test"), ":"])],{},[])
-*** Output of to_html ***
-<p><span>test</span>:</p>
-*** Output of to_latex ***
-test:
-*** Output of to_md ***
-test:
-*** Output of to_s ***
-test:
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/email.md b/tests/unittest/email.md
deleted file mode 100644
index a181504..0000000
--- a/tests/unittest/email.md
+++ /dev/null
@@ -1,32 +0,0 @@
-Write a comment abouth the test here.
-*** Parameters: ***
-{}
-*** Markdown input: ***
-
-
-This is an email address: <andrea at invalid.it>
-	
-*** Output of inspect ***
-md_el(:document,[
-	md_par(["This is an email address: ", md_email("andrea at invalid.it")])
-],{},[])
-*** Output of to_html ***
-<p>This is an email address: <a href='mailto:andrea at invalid.it'>andrea@invalid.it</a></p>
-*** Output of to_latex ***
-This is an email address: \href{mailto:andrea at invalid.it}{andrea\char64invalid\char46it}
-*** Output of to_md ***
-This is an email address:
-*** Output of to_s ***
-This is an email address:
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/hang.md b/tests/unittest/hang.md
deleted file mode 100644
index 949ae5b..0000000
--- a/tests/unittest/hang.md
+++ /dev/null
@@ -1,29 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-deded  {.num_defn #IsbellDuality
-	
-
-*** Output of inspect ***
-md_el(:document,[md_par(["deded"])],{},[])
-*** Output of to_html ***
-<p>deded</p>
-*** Output of to_latex ***
-deded
-*** Output of to_md ***
-deded
-*** Output of to_s ***
-deded
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/html2.md b/tests/unittest/html2.md
deleted file mode 100644
index 72cb516..0000000
--- a/tests/unittest/html2.md
+++ /dev/null
@@ -1,34 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-One
-<div></div>123
-
-<div></div>123
-*** Output of inspect ***
-md_el(:document,[
-	md_par(["One ", md_html("<div></div>"), "123"]),
-	md_html("<div></div>")
-],{},[])
-*** Output of to_html ***
-<p>One <div />123</p>
-<div />
-*** Output of to_latex ***
-One 123
-*** Output of to_md ***
-One 123
-*** Output of to_s ***
-One 123
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/ie.md b/tests/unittest/ie.md
deleted file mode 100644
index c428945..0000000
--- a/tests/unittest/ie.md
+++ /dev/null
@@ -1,61 +0,0 @@
-We must make sure that `'` is always written as `'`.
-
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-`<p>here's an apostrophe & a quote "</p>`
-
-	<p>here's an apostrophe & a quote "</p>
-{:}
-
-	<p>here's an apostrophe & a quote "</p>
-{:lang=xml}
-
-	<p>here's an apostrophe & a quote "</p>
-{:html_use_syntax=true lang=not_supported}
-
-	<p>here's an apostrophe & a quote "</p>
-{:html_use_syntax=true lang=xml}
-
-
-*** Output of inspect ***
-md_el(:document,[
-	md_par([md_code("<p>here's an apostrophe & a quote \"</p>")]),
-	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>"},[]),
-	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>"},[["lang", "xml"]]),
-	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>"},[["html_use_syntax", "true"], ["lang", "not_supported"]]),
-	md_el(:code,[],{:raw_code=>"<p>here's an apostrophe & a quote \"</p>"},[["html_use_syntax", "true"], ["lang", "xml"]])
-],{},[])
-*** Output of to_html ***
-<p><code><p>here's an apostrophe & a quote "</p></code></p>
-
-<pre><code><p>here's an apostrophe & a quote "</p></code></pre>
-
-<pre lang='xml'><code class='xml' lang='xml'><p>here's an apostrophe & a quote "</p></code></pre>
-
-<pre><code class='not_supported' lang='not_supported'><p>here's an apostrophe & a quote "</p></code></pre>
-
-<pre><code class='xml' lang='xml'><span class='punct'><</span><span class='tag'>p</span><span class='punct'>></span>here's an apostrophe & a quote "<span class='punct'></</span><span class='tag'>p</span><span class='punct'>></span></code></pre>
-*** Output of to_latex ***
-{\colorbox[rgb]{1.00,0.93,1.00}{\tt \char60p\char62here\char39s~an~apostrophe~\char38~a~quote~\char34\char60\char47p\char62}}
-
-\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
-\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
-\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
-\begin{verbatim}<p>here's an apostrophe & a quote "</p>\end{verbatim}
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/links2.md b/tests/unittest/links2.md
deleted file mode 100644
index 5255e82..0000000
--- a/tests/unittest/links2.md
+++ /dev/null
@@ -1,34 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-See [foo' bar]
-
-[foo' bar]: http://agorf.gr/
-
-
-*** Output of inspect ***
-md_el(:document,[
-	md_par(["See ", md_link(["foo", md_entity("rsquo"), " bar"],"foo_bar")]),
-	md_ref_def("foo_bar", "http://agorf.gr/", {:title=>nil})
-],{},[])
-*** Output of to_html ***
-<p>See <a href='http://agorf.gr/'>foo’ bar</a></p>
-*** Output of to_latex ***
-See \href{http://agorf.gr/}{foo'{} bar}
-*** Output of to_md ***
-See foo bar
-*** Output of to_s ***
-See foo bar
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/lists11.md b/tests/unittest/lists11.md
deleted file mode 100644
index d3c24e5..0000000
--- a/tests/unittest/lists11.md
+++ /dev/null
@@ -1,28 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-- ένα
-
-*** Output of inspect ***
-md_el(:document,[md_par(["- \316\255\316\275\316\261"])],{},[])
-*** Output of to_html ***
-<p>- ένα</p>
-*** Output of to_latex ***
-- ένα
-*** Output of to_md ***
-- ένα
-*** Output of to_s ***
-- ένα
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/lists6.md b/tests/unittest/lists6.md
deleted file mode 100644
index a479a86..0000000
--- a/tests/unittest/lists6.md
+++ /dev/null
@@ -1,53 +0,0 @@
-## Nested
-
-*	Tab
-	*	Tab
-		*	Tab
-
-Here's another:
-
-1. First
-2. Second:
-	* Fee
-	* Fie
-	* Foe
-3. Third
-
-Same thing but with paragraphs:
-
-1. First
-
-2. Second:
-	* Fee
-	* Fie
-	* Foe
-
-3. Third
-
-
-*** Parameters: ***
-{}
-*** Markdown input: ***
-
-*** Output of inspect ***
-md_el(:document,[],{},[])
-*** Output of to_html ***
-
-*** Output of to_latex ***
-
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/lists9.md b/tests/unittest/lists9.md
deleted file mode 100644
index 5a2885a..0000000
--- a/tests/unittest/lists9.md
+++ /dev/null
@@ -1,76 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-- Due
-  1. tre
-  1. tre
-  1. tre
-- Due
-*** Output of inspect ***
-md_el(:document,[
-	md_el(:ul,[
-		md_el(:li,[
-			md_par(["Due"]),
-			md_el(:ol,[
-				md_el(:li_span,["tre"],{:want_my_paragraph=>false},[]),
-				md_el(:li_span,["tre"],{:want_my_paragraph=>false},[]),
-				md_el(:li_span,["tre"],{:want_my_paragraph=>false},[])
-			],{},[])
-		],{:want_my_paragraph=>true},[]),
-		md_el(:li,[md_par(["Due"])],{:want_my_paragraph=>false},[])
-	],{},[])
-],{},[])
-*** Output of to_html ***
-<ul>
-<li>
-<p>Due</p>
-
-<ol>
-<li>tre</li>
-
-<li>tre</li>
-
-<li>tre</li>
-</ol>
-</li>
-
-<li>
-<p>Due</p>
-</li>
-</ul>
-*** Output of to_latex ***
-\begin{itemize}%
-\item Due
-
-\begin{enumerate}%
-\item tre
-\item tre
-\item tre
-
-\end{enumerate}
-
-\item Due
-
-
-
-\end{itemize}
-*** Output of to_md ***
--ue* tre
-* tre
-* tre
--ue
-*** Output of to_s ***
-DuetretretreDue
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/math/equations.md b/tests/unittest/math/equations.md
deleted file mode 100644
index 0cdb2b8..0000000
--- a/tests/unittest/math/equations.md
+++ /dev/null
@@ -1,86 +0,0 @@
-Write a comment here
-*** Parameters: ***
-require 'maruku/ext/math';{}
-*** Markdown input: ***
-
-$$ x = y $$
-
-$$ x 
-= y $$
-
-$$ 
-x = y $$
-
-$$ x = y 
-$$
-
-*** Output of inspect ***
-md_el(:document,[
-	md_el(:equation,[],{:label=>nil,:math=>" x = y ",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" x = y \n",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" x = y \n",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" x = y \n",:num=>nil},[])
-],{},[])
-*** Output of to_html ***
-<div class='maruku-equation'><code class='maruku-mathml'> x = y </code><div class='maruku-eq-tex'><code style='display: none'>x = y</code></div></div><div class='maruku-equation'><code class='maruku-mathml'> x = y 
-</code><div class='maruku-eq-tex'><code style='display: none'>x = y</code></div></div><div class='maruku-equation'><code class='maruku-mathml'> x = y 
-</code><div class='maruku-eq-tex'><code style='display: none'>x = y</code></div></div><div class='maruku-equation'><code class='maruku-mathml'> x = y 
-</code><div class='maruku-eq-tex'><code style='display: none'>x = y</code></div></div>
-*** Output of to_latex ***
-\begin{displaymath}
-x = y
-\end{displaymath}
-\begin{displaymath}
-x = y
-\end{displaymath}
-\begin{displaymath}
-x = y
-\end{displaymath}
-\begin{displaymath}
-x = y
-\end{displaymath}
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-
-Failed tests:   [:to_html] 
-
-*** Output of inspect ***
-md_el(:document,[
-	md_el(:equation,[],{:label=>nil,:math=>" x = y ",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" x = y \n",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" x = y \n",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" x = y \n",:num=>nil},[])
-],{},[])
-*** Output of to_html ***
------| WARNING | -----
-<div class='maruku-equation'><code class='maruku-mathml'> x = y </code><span class='maruku-eq-tex'><code style='display: none'>x = y</code></span></div><div class='maruku-equation'><code class='maruku-mathml'> x = y 
-</code><span class='maruku-eq-tex'><code style='display: none'>x = y</code></span></div><div class='maruku-equation'><code class='maruku-mathml'> x = y 
-</code><span class='maruku-eq-tex'><code style='display: none'>x = y</code></span></div><div class='maruku-equation'><code class='maruku-mathml'> x = y 
-</code><span class='maruku-eq-tex'><code style='display: none'>x = y</code></span></div>
-*** Output of to_latex ***
-\begin{displaymath}
-x = y
-\end{displaymath}
-\begin{displaymath}
-x = y
-\end{displaymath}
-\begin{displaymath}
-x = y
-\end{displaymath}
-\begin{displaymath}
-x = y
-\end{displaymath}
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/math/inline.md b/tests/unittest/math/inline.md
deleted file mode 100644
index 1599073..0000000
--- a/tests/unittest/math/inline.md
+++ /dev/null
@@ -1,58 +0,0 @@
-
-*** Parameters: ***
-require 'maruku/ext/math'; {}
-*** Markdown input: ***
-Here are some formulas:
-
-*	$\alpha$
-*	$x^{n}+y^{n} \neq z^{n}$
-
-That's it, nothing else is supported.
-
-*** Output of inspect ***
-md_el(:document,[
-	md_par(["Here are some formulas:"]),
-	md_el(:ul,[
-		md_el(:li_span,[md_el(:inline_math,[],{:math=>"\\alpha"},[])],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,[md_el(:inline_math,[],{:math=>"x^{n}+y^{n} \\neq z^{n}"},[])],{:want_my_paragraph=>false},[])
-	],{},[]),
-	md_par(["That", md_entity("rsquo"), "s it, nothing else is supported."])
-],{},[])
-*** Output of to_html ***
-<p>Here are some formulas:</p>
-
-<ul>
-<li><code class='maruku-mathml'>\alpha</code></li>
-
-<li><code class='maruku-mathml'>x^{n}+y^{n} \neq z^{n}</code></li>
-</ul>
-
-<p>That’s it, nothing else is supported.</p>
-*** Output of to_latex ***
-Here are some formulas:
-
-\begin{itemize}%
-\item $\alpha$
-\item $x^{n}+y^{n} \neq z^{n}$
-
-\end{itemize}
-That'{}s it, nothing else is supported.
-*** Output of to_md ***
-Here are some formulas:
-
---
-That s it, nothing else is supported.
-*** Output of to_s ***
-Here are some formulas:Thats it, nothing else is supported.
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/math/math2.md b/tests/unittest/math/math2.md
deleted file mode 100644
index da7edd0..0000000
--- a/tests/unittest/math/math2.md
+++ /dev/null
@@ -1,57 +0,0 @@
-
-*** Parameters: ***
-require 'maruku/ext/math'
-{:math_numbered => ['\\['], :html_math_engine => 'itex2mml' }
-*** Markdown input: ***
-
-\[
-	\alpha
-\]
-
-\begin{equation}
-	\alpha
-\end{equation}
-
-\begin{equation} \beta
-\end{equation}
-
-
-\begin{equation} \gamma \end{equation}
-*** Output of inspect ***
-md_el(:document,[
-	md_el(:equation,[],{:label=>"eq1",:math=>"\t\\alpha\n\n",:num=>1},[]),
-	md_el(:equation,[],{:label=>nil,:math=>"\t\\alpha\n\n",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" \\beta\n",:num=>nil},[]),
-	md_el(:equation,[],{:label=>nil,:math=>" \\gamma ",:num=>nil},[])
-],{},[])
-*** Output of to_html ***
-<div class='maruku-equation' id='eq:eq1'><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'><mi>α</mi></math><span class='maruku-eq-tex'><code style='display: none'>\alpha</code></span><span class='maruku-eq-number'>(1)</span></div><div class='maruku-equation'><math class='maruku-mathml' display='block' xmlns='http://www.w3.org/1998/Math/MathML'><mi>α</mi></math><span class='maruku-eq-tex'><code style='display: none'>\alpha</code></span></d [...]
-*** Output of to_latex ***
-\begin{equation}
-\alpha
-\label{eq1}\end{equation}
-\begin{displaymath}
-\alpha
-\end{displaymath}
-\begin{displaymath}
-\beta
-\end{displaymath}
-\begin{displaymath}
-\gamma
-\end{displaymath}
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/math/table.md b/tests/unittest/math/table.md
deleted file mode 100644
index eaac2ae..0000000
--- a/tests/unittest/math/table.md
+++ /dev/null
@@ -1,37 +0,0 @@
-Write a comment here
-*** Parameters: ***
-require 'maruku/ext/math';{:html_math_engine => 'itex2mml' }
-*** Markdown input: ***
-<table markdown='1'>
-	$\alpha$
-	<thead>
-		<td>$\beta$</td>
-	</thead>
-</table>
-*** Output of inspect ***
-md_el(:document,[
-	md_html("<table markdown='1'>\n\t$\\alpha$\n\t<thead>\n\t\t<td>$\\beta$</td>\n\t</thead>\n</table>")
-],{},[])
-*** Output of to_html ***
-<table><math class='maruku-mathml' display='inline' xmlns='http://www.w3.org/1998/Math/MathML'><mi>α</mi></math><thead>
-		<td><math class='maruku-mathml' display='inline' xmlns='http://www.w3.org/1998/Math/MathML'><mi>β</mi></math></td>
-	</thead>
-</table>
-*** Output of to_latex ***
-
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/notyet/header_after_par.md b/tests/unittest/notyet/header_after_par.md
deleted file mode 100644
index 67219a8..0000000
--- a/tests/unittest/notyet/header_after_par.md
+++ /dev/null
@@ -1,70 +0,0 @@
-Write a comment abouth the test here.
-*** Parameters: ***
-{:title=>"header"}
-*** Markdown input: ***
-Paragraph
-### header ###
-
-Paragraph
-header
-------
-
-Paragraph
-header
-======
-
-*** Output of inspect ***
-md_el(:document,[
-	md_par(["Paragraph"]),
-	md_el(:header,["header"],{:level=>3},[]),
-	md_par(["Paragraph"]),
-	md_el(:header,["header"],{:level=>2},[]),
-	md_par(["Paragraph"]),
-	md_el(:header,["header"],{:level=>1},[])
-],{},[])
-*** Output of to_html ***
-<p>Paragraph</p>
-
-<h3 id='header'>header</h3>
-
-<p>Paragraph</p>
-
-<h2 id='header'>header</h2>
-
-<p>Paragraph</p>
-
-<h1 id='header'>header</h1>
-*** Output of to_latex ***
-Paragraph
-
-\hypertarget{header}{}\subsubsection*{{header}}\label{header}
-
-Paragraph
-
-\hypertarget{header}{}\subsection*{{header}}\label{header}
-
-Paragraph
-
-\hypertarget{header}{}\section*{{header}}\label{header}
-*** Output of to_md ***
-Paragraph
-
-headerParagraph
-
-headerParagraph
-
-header
-*** Output of to_s ***
-ParagraphheaderParagraphheaderParagraphheader
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/pending/empty_cells.md b/tests/unittest/pending/empty_cells.md
deleted file mode 100644
index 23eac13..0000000
--- a/tests/unittest/pending/empty_cells.md
+++ /dev/null
@@ -1,49 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-|    | 1  | 2  |
-|----|----|----|
-|  A | X  |    |
-|  B |    | X  |
-*** Output of inspect ***
-md_el(:document,[
-	md_el(:table,[
-		md_el(:head_cell,[],{},[]),
-		md_el(:head_cell,["1"],{},[]),
-		md_el(:head_cell,["2"],{},[]),
-		md_el(:cell,["A"],{},[]),
-		md_el(:cell,["X"],{},[]),
-		md_el(:cell,[],{},[]),
-		md_el(:cell,["B"],{},[]),
-		md_el(:cell,[],{},[]),
-		md_el(:cell,["X"],{},[])
-	],{:align=>[:left, :left, :left]},[])
-],{},[])
-*** Output of to_html ***
-<table><thead><tr><th /><th>1</th><th>2</th></tr></thead><tbody><tr><td style='text-align: left;'>A</td><td style='text-align: left;'>X</td><td style='text-align: left;' />
-</tr><tr><td style='text-align: left;'>B</td><td style='text-align: left;' /><td style='text-align: left;'>X</td>
-</tr></tbody></table>
-*** Output of to_latex ***
-\begin{tabular}{l|l|l}
-&1&2\\
-\hline 
-A&X&\\
-B&&X\\
-\end{tabular}
-*** Output of to_md ***
-12AXBX
-*** Output of to_s ***
-12AXBX
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/red_tests/abbrev.md b/tests/unittest/red_tests/abbrev.md
deleted file mode 100644
index cef3e28..0000000
--- a/tests/unittest/red_tests/abbrev.md
+++ /dev/null
@@ -1,1388 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-
-WebKit (Safari 3.1) and the CSS @font-face declaration
-======================================================
- 
-I'm a big fan of typography in general. If you check out [my homepage](http://elliottcable.name) or my [contact elliottcable](http://elliottcable.name/contact.xhtml) page, and you're using Safari/WebKit or Opera/Kestrel, you'll notice the typefaces (fonts, as colloquialized) are *very* non-standard. (As of this writing, I'm using [Museo][] and [Diavlo][][^jos] heavily on both.)
- 
-The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We've been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and... dare I invoke ye, thou my terr [...]
- 
-Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world.
- 
-All hyperbole aside, I'm extremely happy to see the advent of a standard `@font-face` declaration in CSS. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary .EOT[^eot] format to appease overly restrictive type foundries' worries about intellectual property (aka. the cold, hard dominatrix that we know only as Ms. Profit) truly and completely killed that initial attempt a [...]
- 
-Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it's an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the 'new' `@font-face` declaration. No, it's not really 'new', but yes, it feels like it is.
- 
-To put it simply, and to be very blunt, it's broken.
- 
-The [CSS spec section][spec] for `@font-face` is very specific - typefaces are to be selected based on a wide array of criteria placed in the `@font-face` declaration block itself. Various textual CSS attributes may be defined within the `@font-face` declaration, and then they will be checked when the typeface is referred to later in the CSS. For instance, if I have two `@font-face` declarations for the Diavlo family - one for regular text, and one for a heavier weighted version of the t [...]
- 
-    @font-face {
-      font-family: 'Diavlo';
-      src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-    }
-    
-    @font-face {
-      font-family: 'Diavlo';
-      font-weight: 900;
-      src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-    }
-    
-    h1, h2, h3, h4, h5, h6 {
-      font-family: 'Diavlo';
-      font-weight: 900;
-    }
-    
-    div#content {
-      font-family: 'Diavlo';
-    }
- 
-As you can see, my headings should use the typeface defined in `Diavlo_Black.otf`, while my body content should use `Diavlo_Book.otf`. However, in WebKit, this doesn't work - it completely ignores any attribute except `font-family:` and `src:` in a `@font-face` declaration! Completely ignores them! Not only that - not *only* that - it disregards all but the last `@font-face` for a given `font-family:` attribute string!
- 
-The implication here is that, to make `@font-face` work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare *completely imaginary, non-existent type families* to satisfy WebKit alone. Here's the method I have used in the places I current implement `@font-face`:
- 
-    @font-face {
-      font-family: 'Diavlo Book';
-      src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-    }
-    
-    @font-face {
-      font-family: 'Diavlo Black';
-      src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-    }
-    
-    h1, h2, h3, h4, h5, h6 {
-      font-family: 'Diavlo Black';
-    }
-    
-    div#content {
-      font-family: 'Diavlo Book';
-    }
- 
-Isn't it horrible? Seriously, my eyes, they bleed. There's lots of problems with this far beyond the lack of semanticity when it comes to the typeface names... let me see how many ways this breaks the purpose of `@font-face`:
- 
- - You remove a large element our control over the display of the page.
- 
-    As soon as we begin to use `@font-face` in our page, we can no longer make any use of any other textual control attribute - `font-weight:`, `font-style:`, and `font-variant:` are no longer available to us, because they no longer correctly map to technical typeface variant/features.
-    
-    Also, many default elements are destroyed, unusable, without 'fixing' - for instance, `<b>` would have no effect in a page styled for WebKit as above; We would have to specify something like `b {font-family: 'Diavlo Black';}` - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design [...]
-    
-    If we want to use Javascript to modify the display of the content, we can't simply adjust the mentioned textual control attributes - we have to know and change the entire `font-family:` array of strings.
- 
- - You make us very wet.
- 
-     And by wet, I mean 'not DRY'. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typeface's bastardized name.
- 
- - You remove our user's user choice, and waste bandwidth.
- 
-    Since the names refer to families that don't, in fact, exist, the browser can't override the declaration with a user's installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won't use that - it doesn't know to use 'Diavlo', which the user has installed, because it was told to use 'Diavlo Black', which no user in the entire world has installed on their computer.
- 
-This whole thing is rather worrying - I've heard Opera has `@font-face` support, though I haven't had time to test this myself, so I don't know if it actually does - or, for that matter, if it does it 'correctly', or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support `@font-face` (Microsoft's unrelated `@font-face` declaration notwithstanding) - I really don't want to see it's early mistakes carried on to FireFox in  [...]
- 
-In summary... come on, WebKit team, this isn't like you - you're always the ones with the closest-to-standard implementation, and the cleanest code, and... hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You're pioneering a leap into the future when it comes to the Web - this is as important, or _more_ important, than Mosiac's allowing of images was.
- 
-To put it succinctly - don't fuck this up, y'all.
- 
-[Museo]: <http://www.josbuivenga.demon.nl/museo.html> (Jos Buivenga's Museo free typeface)
-[Diavlo]: <http://www.josbuivenga.demon.nl/diavlo.html> (Jos Buivenga's free Diavlo typeface)
-[^jos]: These are fonts by [Jos Buivenga][jos], quite the amazing person. His (free) fonts are, uniquely, released for use on the web in `@font-face` declarations - unlike the vast majority of other (even free to download) typefaces, which have ridiculously restricting licenses and terms of use statements. Props, Jos - you're a pioneer, and deserve recognition as such.
-*[CSS]: Cascading Style Sheets
-*[.EOT]: Embedded OpenType
-[^eot]: To give Microsoft a little credit, something I rarely do... Yes, I'm aware Microsoft submitted EOT to the W3C as a proposal - the problem isn't with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry - simply decimated it. Do we really want to see the same thing happen to our beloved medium as typography moves into the 21st century?
-*[W3C]: World Wide Web Consortium
-[W3C]: <http://w3c.org> (World Wide Web Consortium)
-[spec]: <http://?> ()
-*[DRY]: Don't Repeat Yourself
-[jos]: jos
-
-*** Output of inspect ***
-md_el(:document,[
-	md_el(:header,["WebKit (Safari 3.1) and the CSS @font-face declaration"],{:level=>1},[]),
-	md_par([
-		"I",
-		md_entity("rsquo"),
-		"m a big fan of typography in general. If you check out ",
-		md_im_link(["my homepage"], "http://elliottcable.name", nil),
-		" or my ",
-		md_im_link(["contact elliottcable"], "http://elliottcable.name/contact.xhtml", nil),
-		" page, and you",
-		md_entity("rsquo"),
-		"re using Safari/WebKit or Opera/Kestrel, you",
-		md_entity("rsquo"),
-		"ll notice the typefaces (fonts, as colloquialized) are ",
-		md_em(["very"]),
-		" non-standard. (As of this writing, I",
-		md_entity("rsquo"),
-		"m using ",
-		md_link(["Museo"],"museo"),
-		" and ",
-		md_link(["Diavlo"],"diavlo"),
-		md_foot_ref("^jos"),
-		" heavily on both.)"
-	]),
-	md_par([
-		"The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We",
-		md_entity("rsquo"),
-		"ve been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and",
-		md_entity("hellip"),
-		" dare I invoke ye, thou my terrible overlord? Times New Roman."
-	]),
-	md_par([
-		"Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world."
-	]),
-	md_par([
-		"All hyperbole aside, I",
-		md_entity("rsquo"),
-		"m extremely happy to see the advent of a standard ",
-		md_code("@font-face"),
-		" declaration in CSS. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary .EOT",
-		md_foot_ref("^eot"),
-		" format to appease overly restrictive type foundries",
-		md_entity("rsquo"),
-		" worries about intellectual property (aka. the cold, hard dominatrix that we know only as Ms. Profit) truly and completely killed that initial attempt at bringing astute typography and it",
-		md_entity("rsquo"),
-		"s advocates to the web. This new run at ",
-		md_code("@font-face"),
-		" by an established, trusted, and open group (the ",
-		md_link(["W3C"],"w3c"),
-		" itself, responsible for helping to make much of what we use as designers on the web standard and cross-system compatible) has a much better chance, in my humble opinion - and I am quite looking forward to the consequences if it succeeds."
-	]),
-	md_par([
-		"Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it",
-		md_entity("rsquo"),
-		"s an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the ",
-		md_entity("lsquo"),
-		"new",
-		md_entity("rsquo"),
-		" ",
-		md_code("@font-face"),
-		" declaration. No, it",
-		md_entity("rsquo"),
-		"s not really ",
-		md_entity("lsquo"),
-		"new",
-		md_entity("rsquo"),
-		", but yes, it feels like it is."
-	]),
-	md_par([
-		"To put it simply, and to be very blunt, it",
-		md_entity("rsquo"),
-		"s broken."
-	]),
-	md_par([
-		"The ",
-		md_link(["CSS spec section"],"spec"),
-		" for ",
-		md_code("@font-face"),
-		" is very specific - typefaces are to be selected based on a wide array of criteria placed in the ",
-		md_code("@font-face"),
-		" declaration block itself. Various textual CSS attributes may be defined within the ",
-		md_code("@font-face"),
-		" declaration, and then they will be checked when the typeface is referred to later in the CSS. For instance, if I have two ",
-		md_code("@font-face"),
-		" declarations for the Diavlo family - one for regular text, and one for a heavier weighted version of the typeface - then I later utilize Diavlo in a ",
-		md_code("font-family:"),
-		" attribute, it should refer to the basic Diavlo font defined in the first ",
-		md_code("@font-face"),
-		". However, if I were to do the same, but also specify a heavy ",
-		md_code("font-weight:"),
-		", then it should use the heavier version of Diavlo. To place this example in code:"
-	]),
-	md_el(:code,[],{:raw_code=>"@font-face {\n  font-family: 'Diavlo';\n  src: url(./Diavlo/Diavlo_Book.otf) format(\"opentype\");\n}\n\n at font-face {\n  font-family: 'Diavlo';\n  font-weight: 900;\n  src: url(./Diavlo/Diavlo_Black.otf) format(\"opentype\");\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: 'Diavlo';\n  font-weight: 900;\n}\n\ndiv#content {\n  font-family: 'Diavlo';\n}"},[]),
-	md_par([
-		"As you can see, my headings should use the typeface defined in ",
-		md_code("Diavlo_Black.otf"),
-		", while my body content should use ",
-		md_code("Diavlo_Book.otf"),
-		". However, in WebKit, this doesn",
-		md_entity("rsquo"),
-		"t work - it completely ignores any attribute except ",
-		md_code("font-family:"),
-		" and ",
-		md_code("src:"),
-		" in a ",
-		md_code("@font-face"),
-		" declaration! Completely ignores them! Not only that - not ",
-		md_em(["only"]),
-		" that - it disregards all but the last ",
-		md_code("@font-face"),
-		" for a given ",
-		md_code("font-family:"),
-		" attribute string!"
-	]),
-	md_par([
-		"The implication here is that, to make ",
-		md_code("@font-face"),
-		" work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare ",
-		md_em(["completely imaginary, non-existent type families"]),
-		" to satisfy WebKit alone. Here",
-		md_entity("rsquo"),
-		"s the method I have used in the places I current implement ",
-		md_code("@font-face"),
-		":"
-	]),
-	md_el(:code,[],{:raw_code=>"@font-face {\n  font-family: 'Diavlo Book';\n  src: url(./Diavlo/Diavlo_Book.otf) format(\"opentype\");\n}\n\n at font-face {\n  font-family: 'Diavlo Black';\n  src: url(./Diavlo/Diavlo_Black.otf) format(\"opentype\");\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: 'Diavlo Black';\n}\n\ndiv#content {\n  font-family: 'Diavlo Book';\n}"},[]),
-	md_par([
-		"Isn",
-		md_entity("rsquo"),
-		"t it horrible? Seriously, my eyes, they bleed. There",
-		md_entity("rsquo"),
-		"s lots of problems with this far beyond the lack of semanticity when it comes to the typeface names",
-		md_entity("hellip"),
-		" let me see how many ways this breaks the purpose of ",
-		md_code("@font-face"),
-		":"
-	]),
-	md_el(:ul,[
-		md_el(:li,[
-			md_par([
-				"You remove a large element our control over the display of the page."
-			]),
-			md_par([
-				"As soon as we begin to use ",
-				md_code("@font-face"),
-				" in our page, we can no longer make any use of any other textual control attribute - ",
-				md_code("font-weight:"),
-				", ",
-				md_code("font-style:"),
-				", and ",
-				md_code("font-variant:"),
-				" are no longer available to us, because they no longer correctly map to technical typeface variant/features."
-			]),
-			md_par([
-				"Also, many default elements are destroyed, unusable, without ",
-				md_entity("lsquo"),
-				"fixing",
-				md_entity("rsquo"),
-				" - for instance, ",
-				md_code("<b>"),
-				" would have no effect in a page styled for WebKit as above; We would have to specify something like ",
-				md_code("b {font-family: 'Diavlo Black';}"),
-				" - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design and content!), but what about comments forms? Forum posts? Direct HTML-literal quotes?"
-			]),
-			md_par([
-				"If we want to use Javascript to modify the display of the content, we can",
-				md_entity("rsquo"),
-				"t simply adjust the mentioned textual control attributes - we have to know and change the entire ",
-				md_code("font-family:"),
-				" array of strings."
-			])
-		],{:want_my_paragraph=>true},[]),
-		md_el(:li,[
-			md_par(["You make us very wet."]),
-			md_par([
-				"And by wet, I mean ",
-				md_entity("lsquo"),
-				"not DRY",
-				md_entity("rsquo"),
-				". What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typeface",
-				md_entity("rsquo"),
-				"s bastardized name."
-			])
-		],{:want_my_paragraph=>true},[]),
-		md_el(:li,[
-			md_par([
-				"You remove our user",
-				md_entity("rsquo"),
-				"s user choice, and waste bandwidth."
-			]),
-			md_par([
-				"Since the names refer to families that don",
-				md_entity("rsquo"),
-				"t, in fact, exist, the browser can",
-				md_entity("rsquo"),
-				"t override the declaration with a user",
-				md_entity("rsquo"),
-				"s installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won",
-				md_entity("rsquo"),
-				"t use that - it doesn",
-				md_entity("rsquo"),
-				"t know to use ",
-				md_entity("lsquo"),
-				"Diavlo",
-				md_entity("rsquo"),
-				", which the user has installed, because it was told to use ",
-				md_entity("lsquo"),
-				"Diavlo Black",
-				md_entity("rsquo"),
-				", which no user in the entire world has installed on their computer."
-			])
-		],{:want_my_paragraph=>true},[])
-	],{},[]),
-	md_par([
-		"This whole thing is rather worrying - I",
-		md_entity("rsquo"),
-		"ve heard Opera has ",
-		md_code("@font-face"),
-		" support, though I haven",
-		md_entity("rsquo"),
-		"t had time to test this myself, so I don",
-		md_entity("rsquo"),
-		"t know if it actually does - or, for that matter, if it does it ",
-		md_entity("lsquo"),
-		"correctly",
-		md_entity("rsquo"),
-		", or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support ",
-		md_code("@font-face"),
-		" (Microsoft",
-		md_entity("rsquo"),
-		"s unrelated ",
-		md_code("@font-face"),
-		" declaration notwithstanding) - I really don",
-		md_entity("rsquo"),
-		"t want to see it",
-		md_entity("rsquo"),
-		"s early mistakes carried on to FireFox in a few years, and then Internet Explorer a few decades after that. That will leave us stuck with this broken system forever, as it has been demonstrated time and time again that if nobody else supports an old standard correctly, a newcomer to the standard will not do it correctly either. I for one would really, really, hate that."
-	]),
-	md_par([
-		"In summary",
-		md_entity("hellip"),
-		" come on, WebKit team, this isn",
-		md_entity("rsquo"),
-		"t like you - you",
-		md_entity("rsquo"),
-		"re always the ones with the closest-to-standard implementation, and the cleanest code, and",
-		md_entity("hellip"),
-		" hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You",
-		md_entity("rsquo"),
-		"re pioneering a leap into the future when it comes to the Web - this is as important, or ",
-		md_em(["more"]),
-		" important, than Mosiac",
-		md_entity("rsquo"),
-		"s allowing of images was."
-	]),
-	md_par([
-		"To put it succinctly - don",
-		md_entity("rsquo"),
-		"t fuck this up, y",
-		md_entity("rsquo"),
-		"all."
-	]),
-	md_ref_def("museo", "http://www.josbuivenga.demon.nl/museo.html>", {:title=>"Jos Buivenga"}),
-	md_ref_def("diavlo", "http://www.josbuivenga.demon.nl/diavlo.html>", {:title=>"Jos Buivenga"}),
-	md_par([
-		md_em([md_link(["CSS"],"css"), ": Cascading Style Sheets"]),
-		md_link([".EOT"],"eot"),
-		": Embedded OpenType ",
-		md_foot_ref("^eot"),
-		": To give Microsoft a little credit, something I rarely do",
-		md_entity("hellip"),
-		" Yes, I",
-		md_entity("rsquo"),
-		"m aware Microsoft submitted EOT to the W3C as a proposal - the problem isn",
-		md_entity("rsquo"),
-		"t with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry - simply decimated it. Do we really want to see the same thing happen to our beloved medium as typography moves into the 21st century? ",
-		md_em([md_link(["W3C"],"w3c"), ": World Wide Web Consortium"])
-	]),
-	md_ref_def("w3c", "http://w3c.org>", {:title=>"World Wide Web Consortium"}),
-	md_ref_def("spec", "http://?>", {:title=>")   *[DRY]: Don"})
-],{},[])
-*** Output of to_html ***
-<h1 id='webkit_safari_31_and_the_css_fontface_declaration'>WebKit (Safari 3.1) and the CSS @font-face declaration</h1>
-
-<p>I’m a big fan of typography in general. If you check out <a href='http://elliottcable.name'>my homepage</a> or my <a href='http://elliottcable.name/contact.xhtml'>contact elliottcable</a> page, and you’re using Safari/WebKit or Opera/Kestrel, you’ll notice the typefaces (fonts, as colloquialized) are <em>very</em> non-standard. (As of this writing, I’m using <a href='http://www.josbuivenga.demon.nl/museo.html>' title='Jos Buivenga'>Museo</a> and <a href='htt [...]
-
-<p>The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We’ve been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and… dare I invoke ye, [...]
-
-<p>Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world.</p>
-
-<p>All hyperbole aside, I’m extremely happy to see the advent of a standard <code>@font-face</code> declaration in CSS. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary .EOT<sup id='fnref:2'><a href='#fn:2' rel='footnote'>2</a></sup> format to appease overly restrictive type foundries’ worries about intellectual property (aka. the cold, hard dominatrix tha [...]
-
-<p>Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it’s an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the ‘new’ <code>@font-face</code> declaration. No, it’s not really ‘new’, but yes, it feels like it is.</p>
-
-<p>To put it simply, and to be very blunt, it’s broken.</p>
-
-<p>The <a href='http://?>' title=')   *[DRY]: Don'>CSS spec section</a> for <code>@font-face</code> is very specific - typefaces are to be selected based on a wide array of criteria placed in the <code>@font-face</code> declaration block itself. Various textual CSS attributes may be defined within the <code>@font-face</code> declaration, and then they will be checked when the typeface is referred to later in the CSS. For instance, if I have two <code>@font-face</code> declarations for [...]
-
-<pre><code>@font-face {
-  font-family: 'Diavlo';
-  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-}
-
- at font-face {
-  font-family: 'Diavlo';
-  font-weight: 900;
-  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-family: 'Diavlo';
-  font-weight: 900;
-}
-
-div#content {
-  font-family: 'Diavlo';
-}</code></pre>
-
-<p>As you can see, my headings should use the typeface defined in <code>Diavlo_Black.otf</code>, while my body content should use <code>Diavlo_Book.otf</code>. However, in WebKit, this doesn’t work - it completely ignores any attribute except <code>font-family:</code> and <code>src:</code> in a <code>@font-face</code> declaration! Completely ignores them! Not only that - not <em>only</em> that - it disregards all but the last <code>@font-face</code> for a given <code>font-family:</ [...]
-
-<p>The implication here is that, to make <code>@font-face</code> work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare <em>completely imaginary, non-existent type families</em> to satisfy WebKit alone. Here’s the method I have used in the places I current implement <code>@font-face</code>:</p>
-
-<pre><code>@font-face {
-  font-family: 'Diavlo Book';
-  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-}
-
- at font-face {
-  font-family: 'Diavlo Black';
-  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-family: 'Diavlo Black';
-}
-
-div#content {
-  font-family: 'Diavlo Book';
-}</code></pre>
-
-<p>Isn’t it horrible? Seriously, my eyes, they bleed. There’s lots of problems with this far beyond the lack of semanticity when it comes to the typeface names… let me see how many ways this breaks the purpose of <code>@font-face</code>:</p>
-
-<ul>
-<li>
-<p>You remove a large element our control over the display of the page.</p>
-
-<p>As soon as we begin to use <code>@font-face</code> in our page, we can no longer make any use of any other textual control attribute - <code>font-weight:</code>, <code>font-style:</code>, and <code>font-variant:</code> are no longer available to us, because they no longer correctly map to technical typeface variant/features.</p>
-
-<p>Also, many default elements are destroyed, unusable, without ‘fixing’ - for instance, <code><b></code> would have no effect in a page styled for WebKit as above; We would have to specify something like <code>b {font-family: 'Diavlo Black';}</code> - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never u [...]
-
-<p>If we want to use Javascript to modify the display of the content, we can’t simply adjust the mentioned textual control attributes - we have to know and change the entire <code>font-family:</code> array of strings.</p>
-</li>
-
-<li>
-<p>You make us very wet.</p>
-
-<p>And by wet, I mean ‘not DRY’. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typeface’s bastardized name.</p>
-</li>
-
-<li>
-<p>You remove our user’s user choice, and waste bandwidth.</p>
-
-<p>Since the names refer to families that don’t, in fact, exist, the browser can’t override the declaration with a user’s installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won’t use that - it doesn’t know to use ‘Diavlo’, which the user has installed, because it was told to use ‘Diavlo Black’, which no user in the entire world has in [...]
-</li>
-</ul>
-
-<p>This whole thing is rather worrying - I’ve heard Opera has <code>@font-face</code> support, though I haven’t had time to test this myself, so I don’t know if it actually does - or, for that matter, if it does it ‘correctly’, or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support <code>@font-face</code> (Microsoft’s unrelated <code>@font-face</code> declaration notwithstanding) -  [...]
-
-<p>In summary… come on, WebKit team, this isn’t like you - you’re always the ones with the closest-to-standard implementation, and the cleanest code, and… hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You’re pioneering a leap into the future when it comes to the Web - this is as important, or <em>more</em> important, than Mosiac’s allowing of images was.</p>
-
-<p>To put it succinctly - don’t fuck this up, y’all.</p>
-
-<p><em><span>CSS</span>: Cascading Style Sheets</em><span>.EOT</span>: Embedded OpenType <sup id='fnref:3'><a href='#fn:3' rel='footnote'>3</a></sup>: To give Microsoft a little credit, something I rarely do… Yes, I’m aware Microsoft submitted EOT to the W3C as a proposal - the problem isn’t with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry -  [...]
-<div class='footnotes'><hr /><ol /></div>
-*** Output of to_latex ***
-#<NameError: undefined local variable or method `fid' for md_foot_ref("^jos"):MaRuKu::MDElement>
-./lib/maruku/output/to_latex.rb:466:in `to_latex_footnote_reference'
-./lib/maruku/output/to_latex.rb:538:in `send'
-./lib/maruku/output/to_latex.rb:538:in `array_to_latex'
-./lib/maruku/output/to_latex.rb:529:in `each'
-./lib/maruku/output/to_latex.rb:529:in `array_to_latex'
-./lib/maruku/output/to_latex.rb:524:in `children_to_latex'
-./lib/maruku/output/to_latex.rb:158:in `to_latex_paragraph'
-./lib/maruku/output/to_latex.rb:538:in `send'
-./lib/maruku/output/to_latex.rb:538:in `array_to_latex'
-./lib/maruku/output/to_latex.rb:529:in `each'
-./lib/maruku/output/to_latex.rb:529:in `array_to_latex'
-./lib/maruku/output/to_latex.rb:524:in `children_to_latex'
-./lib/maruku/output/to_latex.rb:42:in `to_latex'
-bin/marutest:93:in `send'
-bin/marutest:93:in `run_test'
-bin/marutest:88:in `each'
-bin/marutest:88:in `run_test'
-bin/marutest:262:in `marutest'
-bin/marutest:259:in `each'
-bin/marutest:259:in `marutest'
-bin/marutest:334
-*** Output of to_md ***
-WebKit (Safari 3.1) and the CSS @font-face declarationI m a big fan of typography in general.
-If you check out my homepageor my
-contact elliottcablepage, and you re
-using Safari/WebKit or Opera/Kestrel,
-you ll notice the typefaces (fonts, as
-colloquialized) are verynon-standard.
-(As of this writing, I m using Museoand
-Diavloheavily on both.)
-
-The internet has not be a friendly
-place for typohiles like myself, up to
-this point, at least. One might even
-say it was a frightful, mentally
-scarring environment for those akin to
-yours truly. We ve been restricted to
-reading page after page after page on
-day after day after day for year after
-year after year abominations of markup
-and design enslaved by the horrible
-overlords we know as Lucida, Verdana,
-Arial, Helvetica, Geneva, Georgia,
-Courier, and dare I invoke ye, thou my
-terrible overlord? Times New Roman.
-
-Wherefore art thou, my glorious Archer?
-And thee as well, my beautiful
-Garamond? The technical restrictions of
-that horrible monster we know as the
-Web Browser hath forced us all too long
-to use those most banal, those most
-common, and those most abused, out of
-all of the typefaces of the world.
-
-All hyperbole aside, I m extremely
-happy to see the advent of a standard
-declaration in CSS. Internet Explorer
-first implemented a crutched, basic
-version of this way back in version 4,
-but nothing ever really came of it -
-their decision to create the
-proprietary .EOT format to appease
-overly restrictive type foundries
-worries about intellectual property
-(aka. the cold, hard dominatrix that we
-know only as Ms. Profit) truly and
-completely killed that initial attempt
-at bringing astute typography and it s
-advocates to the web. This new run at
-by an established, trusted, and open
-group (the W3Citself, responsible for
-helping to make much of what we use as
-designers on the web standard and
-cross-system compatible) has a much
-better chance, in my humble opinion -
-and I am quite looking forward to the
-consequences if it succeeds.
-
-Now, onwards to the topic of my post as
-declared in the header (yes, I know, a
-slow start - but it s an interesting
-topic with an interesting history!).
-WebKit, the open source rendering
-engine behind the wonderfulness that is
-Safari, and how it handles the new
-declaration. No, it s not really new ,
-but yes, it feels like it is.
-
-To put it simply, and to be very blunt,
-it s broken.
-
-The CSS spec sectionfor is very
-specific - typefaces are to be selected
-based on a wide array of criteria
-placed in the declaration block itself.
-Various textual CSS attributes may be
-defined within the declaration, and
-then they will be checked when the
-typeface is referred to later in the
-CSS. For instance, if I have two
-declarations for the Diavlo family -
-one for regular text, and one for a
-heavier weighted version of the
-typeface - then I later utilize Diavlo
-in a attribute, it should refer to the
-basic Diavlo font defined in the first
-. However, if I were to do the same,
-but also specify a heavy , then it
-should use the heavier version of
-Diavlo. To place this example in code:
-
-As you can see, my headings should use
-the typeface defined in , while my body
-content should use . However, in
-WebKit, this doesn t work - it
-completely ignores any attribute except
-and in a declaration! Completely
-ignores them! Not only that - not only
-that - it disregards all but the last
-for a given attribute string!
-
-The implication here is that, to make
-work as it is currently implemented in
-WebKit (and thus, Safari 3.1), I have
-to declare
-completely imaginary, non-existent type families
-to satisfy WebKit alone. Here s the
-method I have used in the places I
-current implement :
-
-Isn t it horrible? Seriously, my eyes,
-they bleed. There s lots of problems
-with this far beyond the lack of
-semanticity when it comes to the
-typeface names let me see how many ways
-this breaks the purpose of :
-
--You remove a large element our control over the display of the page.
-As soon as we begin to use  in our page, we can no longer make any use of any other textual control attribute - , , and  are no longer available to us, because they no longer correctly map to technical typeface variant/features.
-Also, many default elements are destroyed, unusable, without fixing - for instance,  would have no effect in a page styled for WebKit as above; We would have to specify something like  - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design and content!), but what about comments forms [...]
-If we want to use Javascript to modify the display of the content, we cant simply adjust the mentioned textual control attributes - we have to know and change the entire  array of strings.
--ou make us very wet.
-And by wet, I mean not DRY. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typefaces bastardized name.
--You remove our users user choice, and waste bandwidth.
-Since the names refer to families that dont, in fact, exist, the browser cant override the declaration with a users installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser wont use that - it doesnt know to use Diavlo, which the user has installed, because it was told to use Diavlo Black, which no user in the entire world has installed on their computer.
-
-This whole thing is rather worrying - I
-ve heard Opera has support, though I
-haven t had time to test this myself,
-so I don t know if it actually does -
-or, for that matter, if it does it
-correctly , or has the same problems as
-WebKit. But either way, WebKit is one
-of the first two implementations to
-ever attempt to support (Microsoft s
-unrelated declaration notwithstanding)
-- I really don t want to see it s early
-mistakes carried on to FireFox in a few
-years, and then Internet Explorer a few
-decades after that. That will leave us
-stuck with this broken system forever,
-as it has been demonstrated time and
-time again that if nobody else supports
-an old standard correctly, a newcomer
-to the standard will not do it
-correctly either. I for one would
-really, really, hate that.
-
-In summary come on, WebKit team, this
-isn t like you - you re always the ones
-with the closest-to-standard
-implementation, and the cleanest code,
-and hell, overall? Webkit is the most
-secure/fastest browser available. But
-this is making me lose my faith in you,
-guys, please get it right. You re
-pioneering a leap into the future when
-it comes to the Web - this is as
-important, or moreimportant, than
-Mosiac s allowing of images was.
-
-To put it succinctly - don t fuck this
-up, y all.
-
-CSS: Cascading Style Sheets.EOT:
-Embedded OpenType : To give Microsoft a
-little credit, something I rarely do
-Yes, I m aware Microsoft submitted EOT
-to the W3C as a proposal - the problem
-isn t with their attempts to make it
-non-proprietary, but with the basic
-concept of making typefaces on the web
-DRMed. Look what such attempts have
-done to the music and video industry -
-simply decimated it. Do we really want
-to see the same thing happen to our
-beloved medium as typography moves into
-the 21st century?
-W3C: World Wide Web Consortium
-*** Output of to_s ***
-WebKit (Safari 3.1) and the CSS @font-face declarationIm a big fan of typography in general. If you check out my homepage or my contact elliottcable page, and youre using Safari/WebKit or Opera/Kestrel, youll notice the typefaces (fonts, as colloquialized) are very non-standard. (As of this writing, Im using Museo and Diavlo heavily on both.)The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scar [...]
-*** EOF ***
-
-
-
-
-Failed tests:   [:inspect, :to_html, :to_latex, :to_md, :to_s] 
-
-*** Output of inspect ***
------| WARNING | -----
-md_el(:document,[
-	md_el(:header,[
-		"WebKit (Safari 3.1) and the ",
-		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
-		" @font-face declaration"
-	],{:level=>1},[]),
-	md_par([
-		"I",
-		md_entity("rsquo"),
-		"m a big fan of typography in general. If you check out ",
-		md_im_link(["my homepage"], "http://elliottcable.name", nil),
-		" or my ",
-		md_im_link(["contact elliottcable"], "http://elliottcable.name/contact.xhtml", nil),
-		" page, and you",
-		md_entity("rsquo"),
-		"re using Safari/WebKit or Opera/Kestrel, you",
-		md_entity("rsquo"),
-		"ll notice the typefaces (fonts, as colloquialized) are ",
-		md_em(["very"]),
-		" non-standard. (As of this writing, I",
-		md_entity("rsquo"),
-		"m using ",
-		md_link(["Museo"],"museo"),
-		" and ",
-		md_link(["Diavlo"],"diavlo"),
-		md_foot_ref("^jos"),
-		" heavily on both.)"
-	]),
-	md_par([
-		"The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We",
-		md_entity("rsquo"),
-		"ve been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and",
-		md_entity("hellip"),
-		" dare I invoke ye, thou my terrible overlord? Times New Roman."
-	]),
-	md_par([
-		"Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world."
-	]),
-	md_par([
-		"All hyperbole aside, I",
-		md_entity("rsquo"),
-		"m extremely happy to see the advent of a standard ",
-		md_code("@font-face"),
-		" declaration in ",
-		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
-		". Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary ",
-		md_el(:abbr,[".EOT"],{:title=>"Embedded OpenType"},[]),
-		md_foot_ref("^eot"),
-		" format to appease overly restrictive type foundries",
-		md_entity("rsquo"),
-		" worries about intellectual property (aka. the cold, hard dominatrix that we know only as Ms. Profit) truly and completely killed that initial attempt at bringing astute typography and it",
-		md_entity("rsquo"),
-		"s advocates to the web. This new run at ",
-		md_code("@font-face"),
-		" by an established, trusted, and open group (the ",
-		md_link([
-			"",
-			md_el(:abbr,["W3C"],{:title=>"World Wide Web Consortium"},[]),
-			""
-		],"w3c"),
-		" itself, responsible for helping to make much of what we use as designers on the web standard and cross-system compatible) has a much better chance, in my humble opinion - and I am quite looking forward to the consequences if it succeeds."
-	]),
-	md_par([
-		"Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it",
-		md_entity("rsquo"),
-		"s an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the ",
-		md_entity("lsquo"),
-		"new",
-		md_entity("rsquo"),
-		" ",
-		md_code("@font-face"),
-		" declaration. No, it",
-		md_entity("rsquo"),
-		"s not really ",
-		md_entity("lsquo"),
-		"new",
-		md_entity("rsquo"),
-		", but yes, it feels like it is."
-	]),
-	md_par([
-		"To put it simply, and to be very blunt, it",
-		md_entity("rsquo"),
-		"s broken."
-	]),
-	md_par([
-		"The ",
-		md_link([
-			md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
-			" spec section"
-		],"spec"),
-		" for ",
-		md_code("@font-face"),
-		" is very specific - typefaces are to be selected based on a wide array of criteria placed in the ",
-		md_code("@font-face"),
-		" declaration block itself. Various textual ",
-		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
-		" attributes may be defined within the ",
-		md_code("@font-face"),
-		" declaration, and then they will be checked when the typeface is referred to later in the ",
-		md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
-		". For instance, if I have two ",
-		md_code("@font-face"),
-		" declarations for the Diavlo family - one for regular text, and one for a heavier weighted version of the typeface - then I later utilize Diavlo in a ",
-		md_code("font-family:"),
-		" attribute, it should refer to the basic Diavlo font defined in the first ",
-		md_code("@font-face"),
-		". However, if I were to do the same, but also specify a heavy ",
-		md_code("font-weight:"),
-		", then it should use the heavier version of Diavlo. To place this example in code:"
-	]),
-	md_el(:code,[],{:raw_code=>"@font-face {\n  font-family: 'Diavlo';\n  src: url(./Diavlo/Diavlo_Book.otf) format(\"opentype\");\n}\n\n at font-face {\n  font-family: 'Diavlo';\n  font-weight: 900;\n  src: url(./Diavlo/Diavlo_Black.otf) format(\"opentype\");\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: 'Diavlo';\n  font-weight: 900;\n}\n\ndiv#content {\n  font-family: 'Diavlo';\n}"},[]),
-	md_par([
-		"As you can see, my headings should use the typeface defined in ",
-		md_code("Diavlo_Black.otf"),
-		", while my body content should use ",
-		md_code("Diavlo_Book.otf"),
-		". However, in WebKit, this doesn",
-		md_entity("rsquo"),
-		"t work - it completely ignores any attribute except ",
-		md_code("font-family:"),
-		" and ",
-		md_code("src:"),
-		" in a ",
-		md_code("@font-face"),
-		" declaration! Completely ignores them! Not only that - not ",
-		md_em(["only"]),
-		" that - it disregards all but the last ",
-		md_code("@font-face"),
-		" for a given ",
-		md_code("font-family:"),
-		" attribute string!"
-	]),
-	md_par([
-		"The implication here is that, to make ",
-		md_code("@font-face"),
-		" work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare ",
-		md_em(["completely imaginary, non-existent type families"]),
-		" to satisfy WebKit alone. Here",
-		md_entity("rsquo"),
-		"s the method I have used in the places I current implement ",
-		md_code("@font-face"),
-		":"
-	]),
-	md_el(:code,[],{:raw_code=>"@font-face {\n  font-family: 'Diavlo Book';\n  src: url(./Diavlo/Diavlo_Book.otf) format(\"opentype\");\n}\n\n at font-face {\n  font-family: 'Diavlo Black';\n  src: url(./Diavlo/Diavlo_Black.otf) format(\"opentype\");\n}\n\nh1, h2, h3, h4, h5, h6 {\n  font-family: 'Diavlo Black';\n}\n\ndiv#content {\n  font-family: 'Diavlo Book';\n}"},[]),
-	md_par([
-		"Isn",
-		md_entity("rsquo"),
-		"t it horrible? Seriously, my eyes, they bleed. There",
-		md_entity("rsquo"),
-		"s lots of problems with this far beyond the lack of semanticity when it comes to the typeface names",
-		md_entity("hellip"),
-		" let me see how many ways this breaks the purpose of ",
-		md_code("@font-face"),
-		":"
-	]),
-	md_el(:ul,[
-		md_el(:li,[
-			md_par([
-				"You remove a large element our control over the display of the page."
-			]),
-			md_par([
-				"As soon as we begin to use ",
-				md_code("@font-face"),
-				" in our page, we can no longer make any use of any other textual control attribute - ",
-				md_code("font-weight:"),
-				", ",
-				md_code("font-style:"),
-				", and ",
-				md_code("font-variant:"),
-				" are no longer available to us, because they no longer correctly map to technical typeface variant/features."
-			]),
-			md_par([
-				"Also, many default elements are destroyed, unusable, without ",
-				md_entity("lsquo"),
-				"fixing",
-				md_entity("rsquo"),
-				" - for instance, ",
-				md_code("<b>"),
-				" would have no effect in a page styled for WebKit as above; We would have to specify something like ",
-				md_code("b {font-family: 'Diavlo Black';}"),
-				" - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design and content!), but what about comments forms? Forum posts? Direct HTML-literal quotes?"
-			]),
-			md_par([
-				"If we want to use Javascript to modify the display of the content, we can",
-				md_entity("rsquo"),
-				"t simply adjust the mentioned textual control attributes - we have to know and change the entire ",
-				md_code("font-family:"),
-				" array of strings."
-			])
-		],{:want_my_paragraph=>true},[]),
-		md_el(:li,[
-			md_par(["You make us very wet."]),
-			md_par([
-				"And by wet, I mean ",
-				md_entity("lsquo"),
-				"not ",
-				md_el(:abbr,["DRY"],{:title=>"Don't Repeat Yourself"},[]),
-				md_entity("rsquo"),
-				". What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our ",
-				md_el(:abbr,["CSS"],{:title=>"Cascading Style Sheets"},[]),
-				", all of our Javascript, and make sure we update every occurrence of the typeface",
-				md_entity("rsquo"),
-				"s bastardized name."
-			])
-		],{:want_my_paragraph=>true},[]),
-		md_el(:li,[
-			md_par([
-				"You remove our user",
-				md_entity("rsquo"),
-				"s user choice, and waste bandwidth."
-			]),
-			md_par([
-				"Since the names refer to families that don",
-				md_entity("rsquo"),
-				"t, in fact, exist, the browser can",
-				md_entity("rsquo"),
-				"t override the declaration with a user",
-				md_entity("rsquo"),
-				"s installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won",
-				md_entity("rsquo"),
-				"t use that - it doesn",
-				md_entity("rsquo"),
-				"t know to use ",
-				md_entity("lsquo"),
-				"Diavlo",
-				md_entity("rsquo"),
-				", which the user has installed, because it was told to use ",
-				md_entity("lsquo"),
-				"Diavlo Black",
-				md_entity("rsquo"),
-				", which no user in the entire world has installed on their computer."
-			])
-		],{:want_my_paragraph=>true},[])
-	],{},[]),
-	md_par([
-		"This whole thing is rather worrying - I",
-		md_entity("rsquo"),
-		"ve heard Opera has ",
-		md_code("@font-face"),
-		" support, though I haven",
-		md_entity("rsquo"),
-		"t had time to test this myself, so I don",
-		md_entity("rsquo"),
-		"t know if it actually does - or, for that matter, if it does it ",
-		md_entity("lsquo"),
-		"correctly",
-		md_entity("rsquo"),
-		", or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support ",
-		md_code("@font-face"),
-		" (Microsoft",
-		md_entity("rsquo"),
-		"s unrelated ",
-		md_code("@font-face"),
-		" declaration notwithstanding) - I really don",
-		md_entity("rsquo"),
-		"t want to see it",
-		md_entity("rsquo"),
-		"s early mistakes carried on to FireFox in a few years, and then Internet Explorer a few decades after that. That will leave us stuck with this broken system forever, as it has been demonstrated time and time again that if nobody else supports an old standard correctly, a newcomer to the standard will not do it correctly either. I for one would really, really, hate that."
-	]),
-	md_par([
-		"In summary",
-		md_entity("hellip"),
-		" come on, WebKit team, this isn",
-		md_entity("rsquo"),
-		"t like you - you",
-		md_entity("rsquo"),
-		"re always the ones with the closest-to-standard implementation, and the cleanest code, and",
-		md_entity("hellip"),
-		" hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You",
-		md_entity("rsquo"),
-		"re pioneering a leap into the future when it comes to the Web - this is as important, or ",
-		md_em(["more"]),
-		" important, than Mosiac",
-		md_entity("rsquo"),
-		"s allowing of images was."
-	]),
-	md_par([
-		"To put it succinctly - don",
-		md_entity("rsquo"),
-		"t fuck this up, y",
-		md_entity("rsquo"),
-		"all."
-	]),
-	md_ref_def("museo", "http://www.josbuivenga.demon.nl/museo.html", {:title=>"Jos Buivenga"}),
-	md_ref_def("diavlo", "http://www.josbuivenga.demon.nl/diavlo.html", {:title=>"Jos Buivenga"}),
-	md_el(:footnote,[
-		md_par([
-			"These are fonts by ",
-			md_link(["Jos Buivenga"],"jos"),
-			", quite the amazing person. His (free) fonts are, uniquely, released for use on the web in ",
-			md_code("@font-face"),
-			" declarations - unlike the vast majority of other (even free to download) typefaces, which have ridiculously restricting licenses and terms of use statements. Props, Jos - you",
-			md_entity("rsquo"),
-			"re a pioneer, and deserve recognition as such."
-		])
-	],{:footnote_id=>"^jos"},[]),
-	md_el(:abbr_def,[],{:abbr=>"CSS",:text=>"Cascading Style Sheets"},[]),
-	md_el(:abbr_def,[],{:abbr=>".EOT",:text=>"Embedded OpenType"},[]),
-	md_el(:footnote,[
-		md_par([
-			"To give Microsoft a little credit, something I rarely do",
-			md_entity("hellip"),
-			" Yes, I",
-			md_entity("rsquo"),
-			"m aware Microsoft submitted EOT to the ",
-			md_el(:abbr,["W3C"],{:title=>"World Wide Web Consortium"},[]),
-			" as a proposal - the problem isn",
-			md_entity("rsquo"),
-			"t with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry - simply decimated it. Do we really want to see the same thing happen to our beloved medium as typography moves into the 21st century?"
-		])
-	],{:footnote_id=>"^eot"},[]),
-	md_el(:abbr_def,[],{:abbr=>"W3C",:text=>"World Wide Web Consortium"},[]),
-	md_ref_def("w3c", "http://w3c.org", {:title=>"World Wide Web Consortium"}),
-	md_ref_def("spec", "http://?", {:title=>nil}),
-	md_el(:abbr_def,[],{:abbr=>"DRY",:text=>"Don't Repeat Yourself"},[]),
-	md_ref_def("jos", "jos", {:title=>nil})
-],{},[])
-*** Output of to_html ***
------| WARNING | -----
-<h1 id='webkit_safari_31_and_the_css_fontface_declaration'>WebKit (Safari 3.1) and the <abbr title='Cascading Style Sheets'>CSS</abbr> @font-face declaration</h1>
-
-<p>I’m a big fan of typography in general. If you check out <a href='http://elliottcable.name'>my homepage</a> or my <a href='http://elliottcable.name/contact.xhtml'>contact elliottcable</a> page, and you’re using Safari/WebKit or Opera/Kestrel, you’ll notice the typefaces (fonts, as colloquialized) are <em>very</em> non-standard. (As of this writing, I’m using <a href='http://www.josbuivenga.demon.nl/museo.html' title='Jos Buivenga'>Museo</a> and <a href='http:// [...]
-
-<p>The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We’ve been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and… dare I invoke ye, [...]
-
-<p>Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world.</p>
-
-<p>All hyperbole aside, I’m extremely happy to see the advent of a standard <code>@font-face</code> declaration in <abbr title='Cascading Style Sheets'>CSS</abbr>. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary <abbr title='Embedded OpenType'>.EOT</abbr><sup id='fnref:2'><a href='#fn:2' rel='footnote'>2</a></sup> format to appease overly restrictive type found [...]
-
-<p>Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it’s an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the ‘new’ <code>@font-face</code> declaration. No, it’s not really ‘new’, but yes, it feels like it is.</p>
-
-<p>To put it simply, and to be very blunt, it’s broken.</p>
-
-<p>The <a href='http://?'><abbr title='Cascading Style Sheets'>CSS</abbr> spec section</a> for <code>@font-face</code> is very specific - typefaces are to be selected based on a wide array of criteria placed in the <code>@font-face</code> declaration block itself. Various textual <abbr title='Cascading Style Sheets'>CSS</abbr> attributes may be defined within the <code>@font-face</code> declaration, and then they will be checked when the typeface is referred to later in the <abbr title=' [...]
-
-<pre><code>@font-face {
-  font-family: 'Diavlo';
-  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-}
-
- at font-face {
-  font-family: 'Diavlo';
-  font-weight: 900;
-  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-family: 'Diavlo';
-  font-weight: 900;
-}
-
-div#content {
-  font-family: 'Diavlo';
-}</code></pre>
-
-<p>As you can see, my headings should use the typeface defined in <code>Diavlo_Black.otf</code>, while my body content should use <code>Diavlo_Book.otf</code>. However, in WebKit, this doesn’t work - it completely ignores any attribute except <code>font-family:</code> and <code>src:</code> in a <code>@font-face</code> declaration! Completely ignores them! Not only that - not <em>only</em> that - it disregards all but the last <code>@font-face</code> for a given <code>font-family:</ [...]
-
-<p>The implication here is that, to make <code>@font-face</code> work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare <em>completely imaginary, non-existent type families</em> to satisfy WebKit alone. Here’s the method I have used in the places I current implement <code>@font-face</code>:</p>
-
-<pre><code>@font-face {
-  font-family: 'Diavlo Book';
-  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-}
-
- at font-face {
-  font-family: 'Diavlo Black';
-  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-family: 'Diavlo Black';
-}
-
-div#content {
-  font-family: 'Diavlo Book';
-}</code></pre>
-
-<p>Isn’t it horrible? Seriously, my eyes, they bleed. There’s lots of problems with this far beyond the lack of semanticity when it comes to the typeface names… let me see how many ways this breaks the purpose of <code>@font-face</code>:</p>
-
-<ul>
-<li>
-<p>You remove a large element our control over the display of the page.</p>
-
-<p>As soon as we begin to use <code>@font-face</code> in our page, we can no longer make any use of any other textual control attribute - <code>font-weight:</code>, <code>font-style:</code>, and <code>font-variant:</code> are no longer available to us, because they no longer correctly map to technical typeface variant/features.</p>
-
-<p>Also, many default elements are destroyed, unusable, without ‘fixing’ - for instance, <code><b></code> would have no effect in a page styled for WebKit as above; We would have to specify something like <code>b {font-family: 'Diavlo Black';}</code> - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never u [...]
-
-<p>If we want to use Javascript to modify the display of the content, we can’t simply adjust the mentioned textual control attributes - we have to know and change the entire <code>font-family:</code> array of strings.</p>
-</li>
-
-<li>
-<p>You make us very wet.</p>
-
-<p>And by wet, I mean ‘not <abbr title='Don't Repeat Yourself'>DRY</abbr>’. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our <abbr title='Cascading Style Sheets'>CSS</abbr>, all of our Javascript, and make sure we update every occurrence of the typeface’s bastardized name.</p>
-</li>
-
-<li>
-<p>You remove our user’s user choice, and waste bandwidth.</p>
-
-<p>Since the names refer to families that don’t, in fact, exist, the browser can’t override the declaration with a user’s installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won’t use that - it doesn’t know to use ‘Diavlo’, which the user has installed, because it was told to use ‘Diavlo Black’, which no user in the entire world has in [...]
-</li>
-</ul>
-
-<p>This whole thing is rather worrying - I’ve heard Opera has <code>@font-face</code> support, though I haven’t had time to test this myself, so I don’t know if it actually does - or, for that matter, if it does it ‘correctly’, or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support <code>@font-face</code> (Microsoft’s unrelated <code>@font-face</code> declaration notwithstanding) -  [...]
-
-<p>In summary… come on, WebKit team, this isn’t like you - you’re always the ones with the closest-to-standard implementation, and the cleanest code, and… hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You’re pioneering a leap into the future when it comes to the Web - this is as important, or <em>more</em> important, than Mosiac’s allowing of images was.</p>
-
-<p>To put it succinctly - don’t fuck this up, y’all.</p>
-<div class='footnotes'><hr /><ol><li id='fn:1'>
-<p>These are fonts by <a href='jos'>Jos Buivenga</a>, quite the amazing person. His (free) fonts are, uniquely, released for use on the web in <code>@font-face</code> declarations - unlike the vast majority of other (even free to download) typefaces, which have ridiculously restricting licenses and terms of use statements. Props, Jos - you’re a pioneer, and deserve recognition as such.</p>
-<a href='#fnref:1' rev='footnote'>↩</a></li><li id='fn:2'>
-<p>To give Microsoft a little credit, something I rarely do… Yes, I’m aware Microsoft submitted EOT to the <abbr title='World Wide Web Consortium'>W3C</abbr> as a proposal - the problem isn’t with their attempts to make it non-proprietary, but with the basic concept of making typefaces on the web DRMed. Look what such attempts have done to the music and video industry - simply decimated it. Do we really want to see the same thing happen to our beloved medium as typograp [...]
-<a href='#fnref:2' rev='footnote'>↩</a></li></ol></div>
-*** Output of to_latex ***
------| WARNING | -----
-\hypertarget{webkit_safari_31_and_the_css_fontface_declaration}{}\section*{{WebKit (Safari 3.1) and the CSS @font-face declaration}}\label{webkit_safari_31_and_the_css_fontface_declaration}
-
-I'{}m a big fan of typography in general. If you check out \href{http://elliottcable.name}{my homepage} or my \href{http://elliottcable.name/contact.xhtml}{contact elliottcable} page, and you'{}re using Safari/WebKit or Opera/Kestrel, you'{}ll notice the typefaces (fonts, as colloquialized) are \emph{very} non-standard. (As of this writing, I'{}m using \href{http://www.josbuivenga.demon.nl/museo.html}{Museo} and \href{http://www.josbuivenga.demon.nl/diavlo.html}{Diavlo}\footnote{These ar [...]
-
-The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scarring environment for those akin to yours truly. We'{}ve been restricted to reading page after page after page on day after day after day for year after year after year abominations of markup and design enslaved by the horrible overlords we know as Lucida, Verdana, Arial, Helvetica, Geneva, Georgia, Courier, and\ldots{} dare I invoke ye, thou  [...]
-
-Wherefore art thou, my glorious Archer? And thee as well, my beautiful Garamond? The technical restrictions of that horrible monster we know as the Web Browser hath forced us all too long to use those most banal, those most common, and those most abused, out of all of the typefaces of the world.
-
-All hyperbole aside, I'{}m extremely happy to see the advent of a standard {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration in CSS. Internet Explorer first implemented a crutched, basic version of this way back in version 4, but nothing ever really came of it - their decision to create the proprietary .EOT\footnote{To give Microsoft a little credit, something I rarely do\ldots{} Yes, I'{}m aware Microsoft submitted EOT to the W3C as a proposal - the problem isn'{} [...]
-
-Now, onwards to the topic of my post as declared in the header (yes, I know, a slow start - but it'{}s an interesting topic with an interesting history!). WebKit, the open source rendering engine behind the wonderfulness that is Safari, and how it handles the `{}new'{} {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration. No, it'{}s not really `{}new'{}, but yes, it feels like it is.
-
-To put it simply, and to be very blunt, it'{}s broken.
-
-The \href{http://?}{CSS spec section} for {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} is very specific - typefaces are to be selected based on a wide array of criteria placed in the {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration block itself. Various textual CSS attributes may be defined within the {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} declaration, and then they will be checked when the typeface is referred to later in the [...]
-
-\begin{verbatim}@font-face {
-  font-family: 'Diavlo';
-  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-}
-
- at font-face {
-  font-family: 'Diavlo';
-  font-weight: 900;
-  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-family: 'Diavlo';
-  font-weight: 900;
-}
-
-div#content {
-  font-family: 'Diavlo';
-}\end{verbatim}
-As you can see, my headings should use the typeface defined in {\colorbox[rgb]{1.00,0.93,1.00}{\tt Diavlo\char95Black\char46otf}}, while my body content should use {\colorbox[rgb]{1.00,0.93,1.00}{\tt Diavlo\char95Book\char46otf}}. However, in WebKit, this doesn'{}t work - it completely ignores any attribute except {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45family\char58}} and {\colorbox[rgb]{1.00,0.93,1.00}{\tt src\char58}} in a {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45f [...]
-
-The implication here is that, to make {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} work as it is currently implemented in WebKit (and thus, Safari 3.1), I have to declare \emph{completely imaginary, non-existent type families} to satisfy WebKit alone. Here'{}s the method I have used in the places I current implement {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}}:
-
-\begin{verbatim}@font-face {
-  font-family: 'Diavlo Book';
-  src: url(./Diavlo/Diavlo_Book.otf) format("opentype");
-}
-
- at font-face {
-  font-family: 'Diavlo Black';
-  src: url(./Diavlo/Diavlo_Black.otf) format("opentype");
-}
-
-h1, h2, h3, h4, h5, h6 {
-  font-family: 'Diavlo Black';
-}
-
-div#content {
-  font-family: 'Diavlo Book';
-}\end{verbatim}
-Isn'{}t it horrible? Seriously, my eyes, they bleed. There'{}s lots of problems with this far beyond the lack of semanticity when it comes to the typeface names\ldots{} let me see how many ways this breaks the purpose of {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}}:
-
-\begin{itemize}%
-\item You remove a large element our control over the display of the page.
-
-As soon as we begin to use {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} in our page, we can no longer make any use of any other textual control attribute - {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45weight\char58}}, {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45style\char58}}, and {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45variant\char58}} are no longer available to us, because they no longer correctly map to technical typeface variant/features.
-
-Also, many default elements are destroyed, unusable, without `{}fixing'{} - for instance, {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char60b\char62}} would have no effect in a page styled for WebKit as above; We would have to specify something like {\colorbox[rgb]{1.00,0.93,1.00}{\tt b~\char123font\char45family\char58~\char39Diavlo~Black\char39\char59\char125}} - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correc [...]
-
-If we want to use Javascript to modify the display of the content, we can'{}t simply adjust the mentioned textual control attributes - we have to know and change the entire {\colorbox[rgb]{1.00,0.93,1.00}{\tt font\char45family\char58}} array of strings.
-
-
-\item You make us very wet.
-
-And by wet, I mean `{}not DRY'{}. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typeface'{}s bastardized name.
-
-
-\item You remove our user'{}s user choice, and waste bandwidth.
-
-Since the names refer to families that don'{}t, in fact, exist, the browser can'{}t override the declaration with a user'{}s installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser won'{}t use that - it doesn'{}t know to use `{}Diavlo'{}, which the user has installed, because it was told to use `{}Diavlo Black'{}, which no user in the entire world has installed on their computer.
-
-
-
-\end{itemize}
-This whole thing is rather worrying - I'{}ve heard Opera has {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} support, though I haven'{}t had time to test this myself, so I don'{}t know if it actually does - or, for that matter, if it does it `{}correctly'{}, or has the same problems as WebKit. But either way, WebKit is one of the first two implementations to ever attempt to support {\colorbox[rgb]{1.00,0.93,1.00}{\tt \char64font\char45face}} (Microsoft'{}s unrelated {\colorb [...]
-
-In summary\ldots{} come on, WebKit team, this isn'{}t like you - you'{}re always the ones with the closest-to-standard implementation, and the cleanest code, and\ldots{} hell, overall? Webkit is the most secure/fastest browser available. But this is making me lose my faith in you, guys, please get it right. You'{}re pioneering a leap into the future when it comes to the Web - this is as important, or \emph{more} important, than Mosiac'{}s allowing of images was.
-
-To put it succinctly - don'{}t fuck this up, y'{}all.
-*** Output of to_md ***
------| WARNING | -----
-WebKit (Safari 3.1) and the CSS @font-face declarationI m a big fan of typography in general.
-If you check out my homepageor my
-contact elliottcablepage, and you re
-using Safari/WebKit or Opera/Kestrel,
-you ll notice the typefaces (fonts, as
-colloquialized) are verynon-standard.
-(As of this writing, I m using Museoand
-Diavloheavily on both.)
-
-The internet has not be a friendly
-place for typohiles like myself, up to
-this point, at least. One might even
-say it was a frightful, mentally
-scarring environment for those akin to
-yours truly. We ve been restricted to
-reading page after page after page on
-day after day after day for year after
-year after year abominations of markup
-and design enslaved by the horrible
-overlords we know as Lucida, Verdana,
-Arial, Helvetica, Geneva, Georgia,
-Courier, and dare I invoke ye, thou my
-terrible overlord? Times New Roman.
-
-Wherefore art thou, my glorious Archer?
-And thee as well, my beautiful
-Garamond? The technical restrictions of
-that horrible monster we know as the
-Web Browser hath forced us all too long
-to use those most banal, those most
-common, and those most abused, out of
-all of the typefaces of the world.
-
-All hyperbole aside, I m extremely
-happy to see the advent of a standard
-declaration in CSS. Internet Explorer
-first implemented a crutched, basic
-version of this way back in version 4,
-but nothing ever really came of it -
-their decision to create the
-proprietary .EOTformat to appease
-overly restrictive type foundries
-worries about intellectual property
-(aka. the cold, hard dominatrix that we
-know only as Ms. Profit) truly and
-completely killed that initial attempt
-at bringing astute typography and it s
-advocates to the web. This new run at
-by an established, trusted, and open
-group (the W3Citself, responsible for
-helping to make much of what we use as
-designers on the web standard and
-cross-system compatible) has a much
-better chance, in my humble opinion -
-and I am quite looking forward to the
-consequences if it succeeds.
-
-Now, onwards to the topic of my post as
-declared in the header (yes, I know, a
-slow start - but it s an interesting
-topic with an interesting history!).
-WebKit, the open source rendering
-engine behind the wonderfulness that is
-Safari, and how it handles the new
-declaration. No, it s not really new ,
-but yes, it feels like it is.
-
-To put it simply, and to be very blunt,
-it s broken.
-
-The CSS spec sectionfor is very
-specific - typefaces are to be selected
-based on a wide array of criteria
-placed in the declaration block itself.
-Various textual CSSattributes may be
-defined within the declaration, and
-then they will be checked when the
-typeface is referred to later in the CSS
-. For instance, if I have two
-declarations for the Diavlo family -
-one for regular text, and one for a
-heavier weighted version of the
-typeface - then I later utilize Diavlo
-in a attribute, it should refer to the
-basic Diavlo font defined in the first
-. However, if I were to do the same,
-but also specify a heavy , then it
-should use the heavier version of
-Diavlo. To place this example in code:
-
-As you can see, my headings should use
-the typeface defined in , while my body
-content should use . However, in
-WebKit, this doesn t work - it
-completely ignores any attribute except
-and in a declaration! Completely
-ignores them! Not only that - not only
-that - it disregards all but the last
-for a given attribute string!
-
-The implication here is that, to make
-work as it is currently implemented in
-WebKit (and thus, Safari 3.1), I have
-to declare
-completely imaginary, non-existent type families
-to satisfy WebKit alone. Here s the
-method I have used in the places I
-current implement :
-
-Isn t it horrible? Seriously, my eyes,
-they bleed. There s lots of problems
-with this far beyond the lack of
-semanticity when it comes to the
-typeface names let me see how many ways
-this breaks the purpose of :
-
--You remove a large element our control over the display of the page.
-As soon as we begin to use  in our page, we can no longer make any use of any other textual control attribute - , , and  are no longer available to us, because they no longer correctly map to technical typeface variant/features.
-Also, many default elements are destroyed, unusable, without fixing - for instance,  would have no effect in a page styled for WebKit as above; We would have to specify something like  - how broken is that? Unless we caught all such default elements and re-styled them to use the bastardized names instead of the correct attributes, lots of basic HTML formatting would be broken. I myself may never use in-document formatting (separation of design and content!), but what about comments forms [...]
-If we want to use Javascript to modify the display of the content, we cant simply adjust the mentioned textual control attributes - we have to know and change the entire  array of strings.
--ou make us very wet.
-And by wet, I mean not DRY. What if we decide to change one of the bastardized font names? Or use a different font entirely? We have to go through all of our CSS, all of our Javascript, and make sure we update every occurrence of the typefaces bastardized name.
--You remove our users user choice, and waste bandwidth.
-Since the names refer to families that dont, in fact, exist, the browser cant override the declaration with a users installed version of the typeface. This means that, regardless of whether the user already has the typeface installed on their own computer, the browser wont use that - it doesnt know to use Diavlo, which the user has installed, because it was told to use Diavlo Black, which no user in the entire world has installed on their computer.
-
-This whole thing is rather worrying - I
-ve heard Opera has support, though I
-haven t had time to test this myself,
-so I don t know if it actually does -
-or, for that matter, if it does it
-correctly , or has the same problems as
-WebKit. But either way, WebKit is one
-of the first two implementations to
-ever attempt to support (Microsoft s
-unrelated declaration notwithstanding)
-- I really don t want to see it s early
-mistakes carried on to FireFox in a few
-years, and then Internet Explorer a few
-decades after that. That will leave us
-stuck with this broken system forever,
-as it has been demonstrated time and
-time again that if nobody else supports
-an old standard correctly, a newcomer
-to the standard will not do it
-correctly either. I for one would
-really, really, hate that.
-
-In summary come on, WebKit team, this
-isn t like you - you re always the ones
-with the closest-to-standard
-implementation, and the cleanest code,
-and hell, overall? Webkit is the most
-secure/fastest browser available. But
-this is making me lose my faith in you,
-guys, please get it right. You re
-pioneering a leap into the future when
-it comes to the Web - this is as
-important, or moreimportant, than
-Mosiac s allowing of images was.
-
-To put it succinctly - don t fuck this
-up, y all.
-
-These are fonts by Jos Buivenga, quite
-the amazing person. His (free) fonts
-are, uniquely, released for use on the
-web in declarations - unlike the vast
-majority of other (even free to
-download) typefaces, which have
-ridiculously restricting licenses and
-terms of use statements. Props, Jos -
-you re a pioneer, and deserve
-recognition as such.
-
-*[CSS]: Cascading Style Sheets
-*[.EOT]: Embedded OpenType
-To give Microsoft a little credit,
-something I rarely do Yes, I m aware
-Microsoft submitted EOT to the W3Cas a
-proposal - the problem isn t with their
-attempts to make it non-proprietary,
-but with the basic concept of making
-typefaces on the web DRMed. Look what
-such attempts have done to the music
-and video industry - simply decimated
-it. Do we really want to see the same
-thing happen to our beloved medium as
-typography moves into the 21st century?
-
-*[W3C]: World Wide Web Consortium
-*[DRY]: Don't Repeat Yourself
-*** Output of to_s ***
------| WARNING | -----
-WebKit (Safari 3.1) and the CSS @font-face declarationIm a big fan of typography in general. If you check out my homepage or my contact elliottcable page, and youre using Safari/WebKit or Opera/Kestrel, youll notice the typefaces (fonts, as colloquialized) are very non-standard. (As of this writing, Im using Museo and Diavlo heavily on both.)The internet has not be a friendly place for typohiles like myself, up to this point, at least. One might even say it was a frightful, mentally scar [...]
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/red_tests/lists7.md b/tests/unittest/red_tests/lists7.md
deleted file mode 100644
index 4568415..0000000
--- a/tests/unittest/red_tests/lists7.md
+++ /dev/null
@@ -1,68 +0,0 @@
-I'm not sure if this should work at all...
-
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-Ciao
-
-*	Tab
-	*	Tab
-		*	Tab
-
-*** Output of inspect ***
-nil
-*** Output of to_html ***
-<p>Ciao</p>
-
-<ul>
-<li>Tab * Tab * Tab</li>
-</ul>
-*** Output of to_latex ***
-Ciao
-
-\begin{itemize}%
-\item Tab * Tab * Tab
-
-\end{itemize}
-*** Output of to_md ***
-Ciao
-
--ab * Tab * Tab
-*** Output of to_s ***
-CiaoTab * Tab * Tab
-*** EOF ***
-
-
-
-
-Failed tests:   [:inspect] 
-
-*** Output of inspect ***
------| WARNING | -----
-md_el(:document,[
-	md_par(["Ciao"]),
-	md_el(:ul,[md_el(:li_span,["Tab * Tab * Tab"],{:want_my_paragraph=>false},[])],{},[])
-],{},[])
-*** Output of to_html ***
-<p>Ciao</p>
-
-<ul>
-<li>Tab * Tab * Tab</li>
-</ul>
-*** Output of to_latex ***
-Ciao
-
-\begin{itemize}%
-\item Tab * Tab * Tab
-
-\end{itemize}
-*** Output of to_md ***
-Ciao
-
--ab * Tab * Tab
-*** Output of to_s ***
-CiaoTab * Tab * Tab
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/red_tests/lists7b.md b/tests/unittest/red_tests/lists7b.md
deleted file mode 100644
index 191a354..0000000
--- a/tests/unittest/red_tests/lists7b.md
+++ /dev/null
@@ -1,128 +0,0 @@
-Test case given by Scott.
-
-http://rubyforge.org/tracker/index.php?func=detail&aid=8862&group_id=2795&atid=10735
-
-a should not be indented.
-
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-* a
-  * a1
-  * a2
-* b
-
-
-*** Output of inspect ***
-md_el(:document,[
-	md_el(:ul,[
-		md_el(:li,[
-			"a",
-			md_el(:ul,[
-				md_el(:li_span,["a1"],{:want_my_paragraph=>false},[]),
-				md_el(:li_span,["a2"],{:want_my_paragraph=>false},[])
-			],{},[])
-		],{:want_my_paragraph=>true},[]),
-		md_el(:li,[md_par(["b"])],{:want_my_paragraph=>false},[])
-	],{},[])
-],{},[])
-*** Output of to_html ***
-<ul>
-<li>
-a
-
-<ul>
-<li>a1</li>
-
-<li>a2</li>
-</ul>
-</li>
-
-<li>
-<p>b</p>
-</li>
-</ul>
-*** Output of to_latex ***
-\begin{itemize}%
-\item a
-
-\begin{itemize}%
-\item a1
-\item a2
-
-\end{itemize}
-
-\item b
-
-
-
-\end{itemize}
-*** Output of to_md ***
--* a1
-* a2
--
-*** Output of to_s ***
-aa1a2b
-*** EOF ***
-
-
-
-
-Failed tests:   [:inspect, :to_html] 
-
-*** Output of inspect ***
------| WARNING | -----
-md_el(:document,[
-	md_el(:ul,[
-		md_el(:li,[
-			md_par(["a"]),
-			md_el(:ul,[
-				md_el(:li_span,["a1"],{:want_my_paragraph=>false},[]),
-				md_el(:li_span,["a2"],{:want_my_paragraph=>false},[])
-			],{},[])
-		],{:want_my_paragraph=>true},[]),
-		md_el(:li,[md_par(["b"])],{:want_my_paragraph=>false},[])
-	],{},[])
-],{},[])
-*** Output of to_html ***
------| WARNING | -----
-<ul>
-<li>
-<p>a</p>
-
-<ul>
-<li>a1</li>
-
-<li>a2</li>
-</ul>
-</li>
-
-<li>
-<p>b</p>
-</li>
-</ul>
-*** Output of to_latex ***
-\begin{itemize}%
-\item a
-
-\begin{itemize}%
-\item a1
-\item a2
-
-\end{itemize}
-
-\item b
-
-
-
-\end{itemize}
-*** Output of to_md ***
--* a1
-* a2
--
-*** Output of to_s ***
-aa1a2b
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/red_tests/lists8.md b/tests/unittest/red_tests/lists8.md
deleted file mode 100644
index 43c10fb..0000000
--- a/tests/unittest/red_tests/lists8.md
+++ /dev/null
@@ -1,76 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{} # params 
-*** Markdown input: ***
-Here is a paragraph.
-
-
-   * Item 1
-   * Item 2
-   * Item 3
-
-*** Output of inspect ***
-md_el(:document,[
-	md_par(["Here is a paragraph."]),
-	md_el(:ul,[
-		md_el(:li_span,["Item 1"],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,["Item 2"],{:want_my_paragraph=>false},[]),
-		md_el(:li_span,["Item 3"],{:want_my_paragraph=>false},[])
-	],{},[])
-],{},[])
-*** Output of to_html ***
-<p>Here is a paragraph.</p>
-
-<ul>
-<li>Item 1</li>
-
-<li>Item 2</li>
-
-<li>Item 3</li>
-</ul>
-*** Output of to_latex ***
-Here is a paragraph.
-
-* Item 1 * Item 2 * Item 3
-*** Output of to_md ***
-Here is a paragraph.
-
--tem 1
--tem 2
--tem 3
-*** Output of to_s ***
-Here is a paragraph.Item 1Item 2Item 3
-*** EOF ***
-
-
-
-
-Failed tests:   [:inspect, :to_html, :to_md, :to_s] 
-
-*** Output of inspect ***
------| WARNING | -----
-md_el(:document,[
-	md_par(["Here is a paragraph."]),
-	md_par(["* Item 1 * Item 2 * Item 3"])
-],{},[])
-*** Output of to_html ***
------| WARNING | -----
-<p>Here is a paragraph.</p>
-
-<p>* Item 1 * Item 2 * Item 3</p>
-*** Output of to_latex ***
-Here is a paragraph.
-
-* Item 1 * Item 2 * Item 3
-*** Output of to_md ***
------| WARNING | -----
-Here is a paragraph.
-
-* Item 1 * Item 2 * Item 3
-*** Output of to_s ***
------| WARNING | -----
-Here is a paragraph.* Item 1 * Item 2 * Item 3
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/red_tests/xml.md b/tests/unittest/red_tests/xml.md
deleted file mode 100644
index 0c304ea..0000000
--- a/tests/unittest/red_tests/xml.md
+++ /dev/null
@@ -1,70 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{:on_error=>:raise}
-*** Markdown input: ***
-
-<img/>
-
-<svg:svg/>
-
-<svg:svg 
-width="600px" height="400px">
-  <svg:g id="group">
-	<svg:circle id="circ1" r="1cm" cx="3cm" cy="3cm" style="fill:red;"></svg:circle>
-	<svg:circle id="circ2" r="1cm" cx="7cm" cy="3cm" style="fill:red;" />
-  </svg:g>
-</svg:svg>
-
-*** Output of inspect ***
-md_el(:document,[
-	md_html("<svg:svg/>"),
-	md_html("<svg:svg \nwidth=\"600px\" height=\"400px\">\n  <svg:g id=\"group\">\n\t<svg:circle id=\"circ1\" r=\"1cm\" cx=\"3cm\" cy=\"3cm\" style=\"fill:red;\"></svg:circle>\n\t<svg:circle id=\"circ2\" r=\"1cm\" cx=\"7cm\" cy=\"3cm\" style=\"fill:red;\" />\n  </svg:g>\n</svg:svg>")
-],{},[])
-*** Output of to_html ***
-<svg:svg /><svg:svg height='400px' width='600px'>
-  <svg:g id='group'>
-	<svg:circle cy='3cm' id='circ1' r='1cm' cx='3cm' style='fill:red;' />
-	<svg:circle cy='3cm' id='circ2' r='1cm' cx='7cm' style='fill:red;' />
-  </svg:g>
-</svg:svg>
-*** Output of to_latex ***
-
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-
-Failed tests:   [:inspect, :to_html] 
-
-*** Output of inspect ***
------| WARNING | -----
-md_el(:document,[
-	md_html("<img />"),
-	md_html("<svg:svg/>"),
-	md_html("<svg:svg \nwidth=\"600px\" height=\"400px\">\n  <svg:g id=\"group\">\n\t<svg:circle id=\"circ1\" r=\"1cm\" cx=\"3cm\" cy=\"3cm\" style=\"fill:red;\"></svg:circle>\n\t<svg:circle id=\"circ2\" r=\"1cm\" cx=\"7cm\" cy=\"3cm\" style=\"fill:red;\" />\n  </svg:g>\n</svg:svg>")
-],{},[])
-*** Output of to_html ***
------| WARNING | -----
-<img /><pre class='markdown-html-error' style='border: solid 3px red; background-color: pink'>REXML could not parse this XML/HTML: 
-<svg:svg/></pre><pre class='markdown-html-error' style='border: solid 3px red; background-color: pink'>REXML could not parse this XML/HTML: 
-<svg:svg 
-width="600px" height="400px">
-  <svg:g id="group">
-	<svg:circle id="circ1" r="1cm" cx="3cm" cy="3cm" style="fill:red;"></svg:circle>
-	<svg:circle id="circ2" r="1cm" cx="7cm" cy="3cm" style="fill:red;" />
-  </svg:g>
-</svg:svg></pre>
-*** Output of to_latex ***
-
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/xml2.md b/tests/unittest/xml2.md
deleted file mode 100644
index 7a91eff..0000000
--- a/tests/unittest/xml2.md
+++ /dev/null
@@ -1,31 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{}
-*** Markdown input: ***
-<!--
-<
--->
-*** Output of inspect ***
-md_el(:document,[md_html("<!--\n<\n-->")],{},[])
-*** Output of to_html ***
-<!--
-<
--->
-*** Output of to_latex ***
-
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/unittest/xml3.md b/tests/unittest/xml3.md
deleted file mode 100644
index b6c8f1c..0000000
--- a/tests/unittest/xml3.md
+++ /dev/null
@@ -1,38 +0,0 @@
-Write a comment here
-*** Parameters: ***
-{}
-*** Markdown input: ***
-<table markdown='1'>
-	Blah
-	<thead>
-		<td>*em*</td>
-	</thead>
-</table>
-
-*** Output of inspect ***
-md_el(:document,[
-	md_html("<table markdown='1'>\n\tBlah\n\t<thead>\n\t\t<td>*em*</td>\n\t</thead>\n</table>")
-],{},[])
-*** Output of to_html ***
-<table>Blah<thead>
-		<td><em>em</em></td>
-	</thead>
-</table>
-*** Output of to_latex ***
-
-*** Output of to_md ***
-
-*** Output of to_s ***
-
-*** EOF ***
-
-
-
-	OK!
-
-
-
-*** Output of Markdown.pl ***
-(not used anymore)
-*** Output of Markdown.pl (parsed) ***
-(not used anymore)
\ No newline at end of file
diff --git a/tests/utf8-files/simple.md b/tests/utf8-files/simple.md
deleted file mode 100644
index 775afd5..0000000
--- a/tests/utf8-files/simple.md
+++ /dev/null
@@ -1 +0,0 @@
-‡
\ No newline at end of file
diff --git a/unit_test_block.sh b/unit_test_block.sh
deleted file mode 100644
index 7f2c108..0000000
--- a/unit_test_block.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-
-files=`find tests/unittest -name '*.md'`
-
-ruby -Ilib bin/marutest $files
-
diff --git a/unit_test_span.sh b/unit_test_span.sh
deleted file mode 100644
index 0d98f4b..0000000
--- a/unit_test_span.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# try  ruby -Ilib lib/maruku/tests/new_parser.rb v b 
-ruby -Ilib lib/maruku/tests/new_parser.rb $* v
-

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-maruku.git



More information about the Pkg-ruby-extras-commits mailing list