public void ReadLine()
		{
			var reader = new CreoleReader("  123 \r\n 456 7890  ");

			var actual = reader.ReadLine();

			Assert.AreEqual("  123 ", actual);
			Assert.AreEqual(7, reader.Position);

			actual = reader.ReadLine();

			Assert.AreEqual(" 456 7890  ", actual);
			Assert.AreEqual(true, reader.EndOfMarkup);
		}
		internal string Parse(string markup, params Func<CreoleReader, CreoleElement>[] ignore)
		{
			var elements = new List<BlockElement>();

			// parse markup
			var reader = new CreoleReader(markup);

			var paragraphBuilder = new StringBuilder();
			while (!reader.EndOfMarkup)
			{
				BlockElement block = null;

				foreach (var blockParser in BlockElements)
				{
					if (ignore.Contains(blockParser))
						continue;

					block = blockParser(reader);
					if (block == null)
						continue;

					break;
				}

				if (block == null)
				{
					paragraphBuilder.AppendLine(reader.ReadLine());
				}
				else
				{
					elements.AddRange(ParagraphBlock.Parse(paragraphBuilder.ToString()));
					paragraphBuilder.Clear();

					elements.Add(block);
				}
			}
			if (paragraphBuilder.Length > 0)
				elements.AddRange(ParagraphBlock.Parse(paragraphBuilder.ToString()));

			// render output
			var writer = new CreoleWriter();

			foreach (var element in elements)
			{
				element.Render(this, writer);
			}

			return writer.ToString().Replace("\n", Environment.NewLine).Trim();
		}