/**
 * marked - a markdown parser
 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
 * https://github.com/chjj/marked
 */

;(function() {

	/**
	 * Block-Level Grammar
	 */

	var block = {
		newline: /^\n+/,
		code: /^( {4}[^\n]+\n*)+/,
		fences: noop,
		hr: /^( *[-*_]){3,} *(?:\n+|$)/,
		heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
		nptable: noop,
		lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
		blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
		list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
		html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
		def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
		table: noop,
		paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
		text: /^[^\n]+/
	};

	block.bullet = /(?:[*+-]|\d+\.)/;
	block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
	block.item = replace(block.item, 'gm')
	(/bull/g, block.bullet)
	();

	block.list = replace(block.list)
	(/bull/g, block.bullet)
	('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
	('def', '\\n+(?=' + block.def.source + ')')
	();

	block.blockquote = replace(block.blockquote)
	('def', block.def)
	();

	block._tag = '(?!(?:'
		+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
		+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
		+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';

	block.html = replace(block.html)
	('comment', /<!--[\s\S]*?-->/)
	('closed', /<(tag)[\s\S]+?<\/\1>/)
	('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
	(/tag/g, block._tag)
	();

	block.paragraph = replace(block.paragraph)
	('hr', block.hr)
	('heading', block.heading)
	('lheading', block.lheading)
	('blockquote', block.blockquote)
	('tag', '<' + block._tag)
	('def', block.def)
	();

	/**
	 * Normal Block Grammar
	 */

	block.normal = merge({}, block);

	/**
	 * GFM Block Grammar
	 */

	block.gfm = merge({}, block.normal, {
		fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
		paragraph: /^/
	});

	block.gfm.paragraph = replace(block.paragraph)
	('(?!', '(?!'
		+ block.gfm.fences.source.replace('\\1', '\\2') + '|'
		+ block.list.source.replace('\\1', '\\3') + '|')
	();

	/**
	 * GFM + Tables Block Grammar
	 */

	block.tables = merge({}, block.gfm, {
		nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
		table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
	});

	/**
	 * Block Lexer
	 */

	function Lexer(options) {
		this.tokens = [];
		this.tokens.links = {};
		this.options = options || marked.defaults;
		this.rules = block.normal;

		if (this.options.gfm) {
			if (this.options.tables) {
				this.rules = block.tables;
			} else {
				this.rules = block.gfm;
			}
		}
	}

	/**
	 * Expose Block Rules
	 */

	Lexer.rules = block;

	/**
	 * Static Lex Method
	 */

	Lexer.lex = function(src, options) {
		var lexer = new Lexer(options);
		return lexer.lex(src);
	};

	/**
	 * Preprocessing
	 */

	Lexer.prototype.lex = function(src) {
		src = src
			.replace(/\r\n|\r/g, '\n')
			.replace(/\t/g, '    ')
			.replace(/\u00a0/g, ' ')
			.replace(/\u2424/g, '\n');

		return this.token(src, true);
	};

	/**
	 * Lexing
	 */

	Lexer.prototype.token = function(src, top, bq) {
		var src = src.replace(/^ +$/gm, '')
			, next
			, loose
			, cap
			, bull
			, b
			, item
			, space
			, i
			, l;

		while (src) {
			// newline
			if (cap = this.rules.newline.exec(src)) {
				src = src.substring(cap[0].length);
				if (cap[0].length > 1) {
					this.tokens.push({
						type: 'space'
					});
				}
			}

			// code
			if (cap = this.rules.code.exec(src)) {
				src = src.substring(cap[0].length);
				cap = cap[0].replace(/^ {4}/gm, '');
				this.tokens.push({
					type: 'code',
					text: !this.options.pedantic
						? cap.replace(/\n+$/, '')
						: cap
				});
				continue;
			}

			// fences (gfm)
			if (cap = this.rules.fences.exec(src)) {
				src = src.substring(cap[0].length);
				this.tokens.push({
					type: 'code',
					lang: cap[2],
					text: cap[3]
				});
				continue;
			}

			// heading
			if (cap = this.rules.heading.exec(src)) {
				src = src.substring(cap[0].length);
				this.tokens.push({
					type: 'heading',
					depth: cap[1].length,
					text: cap[2]
				});
				continue;
			}

			// table no leading pipe (gfm)
			if (top && (cap = this.rules.nptable.exec(src))) {
				src = src.substring(cap[0].length);

				item = {
					type: 'table',
					header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
					align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
					cells: cap[3].replace(/\n$/, '').split('\n')
				};

				for (i = 0; i < item.align.length; i++) {
					if (/^ *-+: *$/.test(item.align[i])) {
						item.align[i] = 'right';
					} else if (/^ *:-+: *$/.test(item.align[i])) {
						item.align[i] = 'center';
					} else if (/^ *:-+ *$/.test(item.align[i])) {
						item.align[i] = 'left';
					} else {
						item.align[i] = null;
					}
				}

				for (i = 0; i < item.cells.length; i++) {
					item.cells[i] = item.cells[i].split(/ *\| */);
				}

				this.tokens.push(item);

				continue;
			}

			// lheading
			if (cap = this.rules.lheading.exec(src)) {
				src = src.substring(cap[0].length);
				this.tokens.push({
					type: 'heading',
					depth: cap[2] === '=' ? 1 : 2,
					text: cap[1]
				});
				continue;
			}

			// hr
			if (cap = this.rules.hr.exec(src)) {
				src = src.substring(cap[0].length);
				this.tokens.push({
					type: 'hr'
				});
				continue;
			}

			// blockquote
			if (cap = this.rules.blockquote.exec(src)) {
				src = src.substring(cap[0].length);

				this.tokens.push({
					type: 'blockquote_start'
				});

				cap = cap[0].replace(/^ *> ?/gm, '');

				// Pass `top` to keep the current
				// "toplevel" state. This is exactly
				// how markdown.pl works.
				this.token(cap, top, true);

				this.tokens.push({
					type: 'blockquote_end'
				});

				continue;
			}

			// list
			if (cap = this.rules.list.exec(src)) {
				src = src.substring(cap[0].length);
				bull = cap[2];

				this.tokens.push({
					type: 'list_start',
					ordered: bull.length > 1
				});

				// Get each top-level item.
				cap = cap[0].match(this.rules.item);

				next = false;
				l = cap.length;
				i = 0;

				for (; i < l; i++) {
					item = cap[i];

					// Remove the list item's bullet
					// so it is seen as the next token.
					space = item.length;
					item = item.replace(/^ *([*+-]|\d+\.) +/, '');

					// Outdent whatever the
					// list item contains. Hacky.
					if (~item.indexOf('\n ')) {
						space -= item.length;
						item = !this.options.pedantic
							? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
							: item.replace(/^ {1,4}/gm, '');
					}

					// Determine whether the next list item belongs here.
					// Backpedal if it does not belong in this list.
					if (this.options.smartLists && i !== l - 1) {
						b = block.bullet.exec(cap[i + 1])[0];
						if (bull !== b && !(bull.length > 1 && b.length > 1)) {
							src = cap.slice(i + 1).join('\n') + src;
							i = l - 1;
						}
					}

					// Determine whether item is loose or not.
					// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
					// for discount behavior.
					loose = next || /\n\n(?!\s*$)/.test(item);
					if (i !== l - 1) {
						next = item.charAt(item.length - 1) === '\n';
						if (!loose) loose = next;
					}

					this.tokens.push({
						type: loose
							? 'loose_item_start'
							: 'list_item_start'
					});

					// Recurse.
					this.token(item, false, bq);

					this.tokens.push({
						type: 'list_item_end'
					});
				}

				this.tokens.push({
					type: 'list_end'
				});

				continue;
			}

			// html
			if (cap = this.rules.html.exec(src)) {
				src = src.substring(cap[0].length);
				this.tokens.push({
					type: this.options.sanitize
						? 'paragraph'
						: 'html',
					pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
					text: cap[0]
				});
				continue;
			}

			// def
			if ((!bq && top) && (cap = this.rules.def.exec(src))) {
				src = src.substring(cap[0].length);
				this.tokens.links[cap[1].toLowerCase()] = {
					href: cap[2],
					title: cap[3]
				};
				continue;
			}

			// table (gfm)
			if (top && (cap = this.rules.table.exec(src))) {
				src = src.substring(cap[0].length);

				item = {
					type: 'table',
					header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
					align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
					cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
				};

				for (i = 0; i < item.align.length; i++) {
					if (/^ *-+: *$/.test(item.align[i])) {
						item.align[i] = 'right';
					} else if (/^ *:-+: *$/.test(item.align[i])) {
						item.align[i] = 'center';
					} else if (/^ *:-+ *$/.test(item.align[i])) {
						item.align[i] = 'left';
					} else {
						item.align[i] = null;
					}
				}

				for (i = 0; i < item.cells.length; i++) {
					item.cells[i] = item.cells[i]
						.replace(/^ *\| *| *\| *$/g, '')
						.split(/ *\| */);
				}

				this.tokens.push(item);

				continue;
			}

			// top-level paragraph
			if (top && (cap = this.rules.paragraph.exec(src))) {
				src = src.substring(cap[0].length);
				this.tokens.push({
					type: 'paragraph',
					text: cap[1].charAt(cap[1].length - 1) === '\n'
						? cap[1].slice(0, -1)
						: cap[1]
				});
				continue;
			}

			// text
			if (cap = this.rules.text.exec(src)) {
				// Top-level should never reach here.
				src = src.substring(cap[0].length);
				this.tokens.push({
					type: 'text',
					text: cap[0]
				});
				continue;
			}

			if (src) {
				throw new
					Error('Infinite loop on byte: ' + src.charCodeAt(0));
			}
		}

		return this.tokens;
	};

	/**
	 * Inline-Level Grammar
	 */

	var inline = {
		escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
		autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
		url: noop,
		tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
		link: /^!?\[(inside)\]\(href\)/,
		reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
		nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
		strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
		em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
		code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
		br: /^ {2,}\n(?!\s*$)/,
		del: noop,
		text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
	};

	inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
	inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;

	inline.link = replace(inline.link)
	('inside', inline._inside)
	('href', inline._href)
	();

	inline.reflink = replace(inline.reflink)
	('inside', inline._inside)
	();

	/**
	 * Normal Inline Grammar
	 */

	inline.normal = merge({}, inline);

	/**
	 * Pedantic Inline Grammar
	 */

	inline.pedantic = merge({}, inline.normal, {
		strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
		em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
	});

	/**
	 * GFM Inline Grammar
	 */

	inline.gfm = merge({}, inline.normal, {
		escape: replace(inline.escape)('])', '~|])')(),
		url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
		del: /^~~(?=\S)([\s\S]*?\S)~~/,
		text: replace(inline.text)
		(']|', '~]|')
		('|', '|https?://|')
		()
	});

	/**
	 * GFM + Line Breaks Inline Grammar
	 */

	inline.breaks = merge({}, inline.gfm, {
		br: replace(inline.br)('{2,}', '*')(),
		text: replace(inline.gfm.text)('{2,}', '*')()
	});

	/**
	 * Inline Lexer & Compiler
	 */

	function InlineLexer(links, options) {
		this.options = options || marked.defaults;
		this.links = links;
		this.rules = inline.normal;
		this.renderer = this.options.renderer || new Renderer;
		this.renderer.options = this.options;

		if (!this.links) {
			throw new
				Error('Tokens array requires a `links` property.');
		}

		if (this.options.gfm) {
			if (this.options.breaks) {
				this.rules = inline.breaks;
			} else {
				this.rules = inline.gfm;
			}
		} else if (this.options.pedantic) {
			this.rules = inline.pedantic;
		}
	}

	/**
	 * Expose Inline Rules
	 */

	InlineLexer.rules = inline;

	/**
	 * Static Lexing/Compiling Method
	 */

	InlineLexer.output = function(src, links, options) {
		var inline = new InlineLexer(links, options);
		return inline.output(src);
	};

	/**
	 * Lexing/Compiling
	 */

	InlineLexer.prototype.output = function(src) {
		var out = ''
			, link
			, text
			, href
			, cap;

		while (src) {
			// escape
			if (cap = this.rules.escape.exec(src)) {
				src = src.substring(cap[0].length);
				out += cap[1];
				continue;
			}

			// autolink
			if (cap = this.rules.autolink.exec(src)) {
				src = src.substring(cap[0].length);
				if (cap[2] === '@') {
					text = cap[1].charAt(6) === ':'
						? this.mangle(cap[1].substring(7))
						: this.mangle(cap[1]);
					href = this.mangle('mailto:') + text;
				} else {
					text = escape(cap[1]);
					href = text;
				}
				out += this.renderer.link(href, null, text);
				continue;
			}

			// url (gfm)
			if (!this.inLink && (cap = this.rules.url.exec(src))) {
				src = src.substring(cap[0].length);
				text = escape(cap[1]);
				href = text;
				out += this.renderer.link(href, null, text);
				continue;
			}

			// tag
			if (cap = this.rules.tag.exec(src)) {
				if (!this.inLink && /^<a /i.test(cap[0])) {
					this.inLink = true;
				} else if (this.inLink && /^<\/a>/i.test(cap[0])) {
					this.inLink = false;
				}
				src = src.substring(cap[0].length);
				out += this.options.sanitize
					? escape(cap[0])
					: cap[0];
				continue;
			}

			// link
			if (cap = this.rules.link.exec(src)) {
				src = src.substring(cap[0].length);
				this.inLink = true;
				out += this.outputLink(cap, {
					href: cap[2],
					title: cap[3]
				});
				this.inLink = false;
				continue;
			}

			// reflink, nolink
			if ((cap = this.rules.reflink.exec(src))
				|| (cap = this.rules.nolink.exec(src))) {
				src = src.substring(cap[0].length);
				link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
				link = this.links[link.toLowerCase()];
				if (!link || !link.href) {
					out += cap[0].charAt(0);
					src = cap[0].substring(1) + src;
					continue;
				}
				this.inLink = true;
				out += this.outputLink(cap, link);
				this.inLink = false;
				continue;
			}

			// strong
			if (cap = this.rules.strong.exec(src)) {
				src = src.substring(cap[0].length);
				out += this.renderer.strong(this.output(cap[2] || cap[1]));
				continue;
			}

			// em
			if (cap = this.rules.em.exec(src)) {
				src = src.substring(cap[0].length);
				out += this.renderer.em(this.output(cap[2] || cap[1]));
				continue;
			}

			// code
			if (cap = this.rules.code.exec(src)) {
				src = src.substring(cap[0].length);
				out += this.renderer.codespan(escape(cap[2], true));
				continue;
			}

			// br
			if (cap = this.rules.br.exec(src)) {
				src = src.substring(cap[0].length);
				out += this.renderer.br();
				continue;
			}

			// del (gfm)
			if (cap = this.rules.del.exec(src)) {
				src = src.substring(cap[0].length);
				out += this.renderer.del(this.output(cap[1]));
				continue;
			}

			// text
			if (cap = this.rules.text.exec(src)) {
				src = src.substring(cap[0].length);
				out += escape(this.smartypants(cap[0]));
				continue;
			}

			if (src) {
				throw new
					Error('Infinite loop on byte: ' + src.charCodeAt(0));
			}
		}

		return out;
	};

	/**
	 * Compile Link
	 */

	InlineLexer.prototype.outputLink = function(cap, link) {
		var href = escape(link.href)
			, title = link.title ? escape(link.title) : null;

		return cap[0].charAt(0) !== '!'
			? this.renderer.link(href, title, this.output(cap[1]))
			: this.renderer.image(href, title, escape(cap[1]));
	};

	/**
	 * Smartypants Transformations
	 */

	InlineLexer.prototype.smartypants = function(text) {
		if (!this.options.smartypants) return text;
		return text
			// em-dashes
			.replace(/--/g, '\u2014')
			// opening singles
			.replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
			// closing singles & apostrophes
			.replace(/'/g, '\u2019')
			// opening doubles
			.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
			// closing doubles
			.replace(/"/g, '\u201d')
			// ellipses
			.replace(/\.{3}/g, '\u2026');
	};

	/**
	 * Mangle Links
	 */

	InlineLexer.prototype.mangle = function(text) {
		var out = ''
			, l = text.length
			, i = 0
			, ch;

		for (; i < l; i++) {
			ch = text.charCodeAt(i);
			if (Math.random() > 0.5) {
				ch = 'x' + ch.toString(16);
			}
			out += '&#' + ch + ';';
		}

		return out;
	};

	/**
	 * Renderer
	 */

	function Renderer(options) {
		this.options = options || {};
	}

	Renderer.prototype.code = function(code, lang, escaped) {
		if (this.options.highlight) {
			var out = this.options.highlight(code, lang);
			if (out != null && out !== code) {
				escaped = true;
				code = out;
			}
		}

		if (!lang) {
			return '<pre><code>'
				+ (escaped ? code : escape(code, true))
				+ '\n</code></pre>';
		}

		return '<pre><code class="'
			+ this.options.langPrefix
			+ escape(lang, true)
			+ '">'
			+ (escaped ? code : escape(code, true))
			+ '\n</code></pre>\n';
	};

	Renderer.prototype.blockquote = function(quote) {
		return '<blockquote>\n' + quote + '</blockquote>\n';
	};

	Renderer.prototype.html = function(html) {
		return html;
	};

	Renderer.prototype.heading = function(text, level, raw) {
		return '<h'
			+ level
			+ ' id="'
			+ this.options.headerPrefix
			+ raw.toLowerCase().replace(/[^\w]+/g, '-')
			+ '">'
			+ text
			+ '</h'
			+ level
			+ '>\n';
	};

	Renderer.prototype.hr = function() {
		return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
	};

	Renderer.prototype.list = function(body, ordered) {
		var type = ordered ? 'ol' : 'ul';
		return '<' + type + '>\n' + body + '</' + type + '>\n';
	};

	Renderer.prototype.listitem = function(text) {
		return '<li>' + text + '</li>\n';
	};

	Renderer.prototype.paragraph = function(text) {
		return '<p>' + text + '</p>\n';
	};

	Renderer.prototype.table = function(header, body) {
		return '<table>\n'
			+ '<thead>\n'
			+ header
			+ '</thead>\n'
			+ '<tbody>\n'
			+ body
			+ '</tbody>\n'
			+ '</table>\n';
	};

	Renderer.prototype.tablerow = function(content) {
		return '<tr>\n' + content + '</tr>\n';
	};

	Renderer.prototype.tablecell = function(content, flags) {
		var type = flags.header ? 'th' : 'td';
		var tag = flags.align
			? '<' + type + ' style="text-align:' + flags.align + '">'
			: '<' + type + '>';
		return tag + content + '</' + type + '>\n';
	};

// span level renderer
	Renderer.prototype.strong = function(text) {
		return '<strong>' + text + '</strong>';
	};

	Renderer.prototype.em = function(text) {
		return '<em>' + text + '</em>';
	};

	Renderer.prototype.codespan = function(text) {
		return '<code>' + text + '</code>';
	};

	Renderer.prototype.br = function() {
		return this.options.xhtml ? '<br/>' : '<br>';
	};

	Renderer.prototype.del = function(text) {
		return '<del>' + text + '</del>';
	};

	Renderer.prototype.link = function(href, title, text) {
		if (this.options.sanitize) {
			try {
				var prot = decodeURIComponent(unescape(href))
					.replace(/[^\w:]/g, '')
					.toLowerCase();
			} catch (e) {
				return '';
			}
			if (prot.indexOf('javascript:') === 0) {
				return '';
			}
		}
		var out = '<a href="' + href + '"';
		if (title) {
			out += ' title="' + title + '"';
		}
		out += '>' + text + '</a>';
		return out;
	};

	Renderer.prototype.image = function(href, title, text) {
		var out = '<img src="' + href + '" alt="' + text + '"';
		if (title) {
			out += ' title="' + title + '"';
		}
		out += this.options.xhtml ? '/>' : '>';
		return out;
	};

	/**
	 * Parsing & Compiling
	 */

	function Parser(options) {
		this.tokens = [];
		this.token = null;
		this.options = options || marked.defaults;
		this.options.renderer = this.options.renderer || new Renderer;
		this.renderer = this.options.renderer;
		this.renderer.options = this.options;
	}

	/**
	 * Static Parse Method
	 */

	Parser.parse = function(src, options, renderer) {
		var parser = new Parser(options, renderer);
		return parser.parse(src);
	};

	/**
	 * Parse Loop
	 */

	Parser.prototype.parse = function(src) {
		this.inline = new InlineLexer(src.links, this.options, this.renderer);
		this.tokens = src.reverse();

		var out = '';
		while (this.next()) {
			out += this.tok();
		}

		return out;
	};

	/**
	 * Next Token
	 */

	Parser.prototype.next = function() {
		return this.token = this.tokens.pop();
	};

	/**
	 * Preview Next Token
	 */

	Parser.prototype.peek = function() {
		return this.tokens[this.tokens.length - 1] || 0;
	};

	/**
	 * Parse Text Tokens
	 */

	Parser.prototype.parseText = function() {
		var body = this.token.text;

		while (this.peek().type === 'text') {
			body += '\n' + this.next().text;
		}

		return this.inline.output(body);
	};

	/**
	 * Parse Current Token
	 */

	Parser.prototype.tok = function() {
		switch (this.token.type) {
			case 'space': {
				return '';
			}
			case 'hr': {
				return this.renderer.hr();
			}
			case 'heading': {
				return this.renderer.heading(
					this.inline.output(this.token.text),
					this.token.depth,
					this.token.text);
			}
			case 'code': {
				return this.renderer.code(this.token.text,
					this.token.lang,
					this.token.escaped);
			}
			case 'table': {
				var header = ''
					, body = ''
					, i
					, row
					, cell
					, flags
					, j;

				// header
				cell = '';
				for (i = 0; i < this.token.header.length; i++) {
					flags = { header: true, align: this.token.align[i] };
					cell += this.renderer.tablecell(
						this.inline.output(this.token.header[i]),
						{ header: true, align: this.token.align[i] }
					);
				}
				header += this.renderer.tablerow(cell);

				for (i = 0; i < this.token.cells.length; i++) {
					row = this.token.cells[i];

					cell = '';
					for (j = 0; j < row.length; j++) {
						cell += this.renderer.tablecell(
							this.inline.output(row[j]),
							{ header: false, align: this.token.align[j] }
						);
					}

					body += this.renderer.tablerow(cell);
				}
				return this.renderer.table(header, body);
			}
			case 'blockquote_start': {
				var body = '';

				while (this.next().type !== 'blockquote_end') {
					body += this.tok();
				}

				return this.renderer.blockquote(body);
			}
			case 'list_start': {
				var body = ''
					, ordered = this.token.ordered;

				while (this.next().type !== 'list_end') {
					body += this.tok();
				}

				return this.renderer.list(body, ordered);
			}
			case 'list_item_start': {
				var body = '';

				while (this.next().type !== 'list_item_end') {
					body += this.token.type === 'text'
						? this.parseText()
						: this.tok();
				}

				return this.renderer.listitem(body);
			}
			case 'loose_item_start': {
				var body = '';

				while (this.next().type !== 'list_item_end') {
					body += this.tok();
				}

				return this.renderer.listitem(body);
			}
			case 'html': {
				var html = !this.token.pre && !this.options.pedantic
					? this.inline.output(this.token.text)
					: this.token.text;
				return this.renderer.html(html);
			}
			case 'paragraph': {
				return this.renderer.paragraph(this.inline.output(this.token.text));
			}
			case 'text': {
				return this.renderer.paragraph(this.parseText());
			}
		}
	};

	/**
	 * Helpers
	 */

	function escape(html, encode) {
		return html
			.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/"/g, '&quot;')
			.replace(/'/g, '&#39;');
	}

	function unescape(html) {
		return html.replace(/&([#\w]+);/g, function(_, n) {
			n = n.toLowerCase();
			if (n === 'colon') return ':';
			if (n.charAt(0) === '#') {
				return n.charAt(1) === 'x'
					? String.fromCharCode(parseInt(n.substring(2), 16))
					: String.fromCharCode(+n.substring(1));
			}
			return '';
		});
	}

	function replace(regex, opt) {
		regex = regex.source;
		opt = opt || '';
		return function self(name, val) {
			if (!name) return new RegExp(regex, opt);
			val = val.source || val;
			val = val.replace(/(^|[^\[])\^/g, '$1');
			regex = regex.replace(name, val);
			return self;
		};
	}

	function noop() {}
	noop.exec = noop;

	function merge(obj) {
		var i = 1
			, target
			, key;

		for (; i < arguments.length; i++) {
			target = arguments[i];
			for (key in target) {
				if (Object.prototype.hasOwnProperty.call(target, key)) {
					obj[key] = target[key];
				}
			}
		}

		return obj;
	}


	/**
	 * Marked
	 */

	function marked(src, opt, callback) {
		if (callback || typeof opt === 'function') {
			if (!callback) {
				callback = opt;
				opt = null;
			}

			opt = merge({}, marked.defaults, opt || {});

			var highlight = opt.highlight
				, tokens
				, pending
				, i = 0;

			try {
				tokens = Lexer.lex(src, opt)
			} catch (e) {
				return callback(e);
			}

			pending = tokens.length;

			var done = function(err) {
				if (err) {
					opt.highlight = highlight;
					return callback(err);
				}

				var out;

				try {
					out = Parser.parse(tokens, opt);
				} catch (e) {
					err = e;
				}

				opt.highlight = highlight;

				return err
					? callback(err)
					: callback(null, out);
			};

			if (!highlight || highlight.length < 3) {
				return done();
			}

			delete opt.highlight;

			if (!pending) return done();

			for (; i < tokens.length; i++) {
				(function(token) {
					if (token.type !== 'code') {
						return --pending || done();
					}
					return highlight(token.text, token.lang, function(err, code) {
						if (err) return done(err);
						if (code == null || code === token.text) {
							return --pending || done();
						}
						token.text = code;
						token.escaped = true;
						--pending || done();
					});
				})(tokens[i]);
			}

			return;
		}
		try {
			if (opt) opt = merge({}, marked.defaults, opt);
			return Parser.parse(Lexer.lex(src, opt), opt);
		} catch (e) {
			e.message += '\nPlease report this to https://github.com/chjj/marked.';
			if ((opt || marked.defaults).silent) {
				return '<p>An error occured:</p><pre>'
					+ escape(e.message + '', true)
					+ '</pre>';
			}
			throw e;
		}
	}

	/**
	 * Options
	 */

	marked.options =
		marked.setOptions = function(opt) {
			merge(marked.defaults, opt);
			return marked;
		};

	marked.defaults = {
		gfm: true,
		tables: true,
		breaks: false,
		pedantic: false,
		sanitize: false,
		smartLists: false,
		silent: false,
		highlight: null,
		langPrefix: 'lang-',
		smartypants: false,
		headerPrefix: '',
		renderer: new Renderer,
		xhtml: false
	};

	/**
	 * Expose
	 */

	marked.Parser = Parser;
	marked.parser = Parser.parse;

	marked.Renderer = Renderer;

	marked.Lexer = Lexer;
	marked.lexer = Lexer.lex;

	marked.InlineLexer = InlineLexer;
	marked.inlineLexer = InlineLexer.output;

	marked.parse = marked;

	if (typeof module !== 'undefined' && typeof exports === 'object') {
		module.exports = marked;
	} else if (typeof define === 'function' && define.amd) {
		define(function() { return marked; });
	} else {
		this.marked = marked;
	}

}).call(function() {
		return this || (typeof window !== 'undefined' ? window : global);
	}());