GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — develop (#163)
by
unknown
09:22
created
application/helpers/markdown_extended_helper.php 1 patch
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -1,98 +1,98 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (! function_exists('Markdown')) {
4
-    require_once('markdown_helper.php');
4
+	require_once('markdown_helper.php');
5 5
 }
6 6
 define('MARKDOWNEXTRAEXTENDED_VERSION', "0.3");
7 7
 
8 8
 function MarkdownExtended($text, $default_classes = array())
9 9
 {
10
-    $parser = new MarkdownExtraExtended_Parser($default_classes);
11
-    return $parser->transform($text);
10
+	$parser = new MarkdownExtraExtended_Parser($default_classes);
11
+	return $parser->transform($text);
12 12
 }
13 13
 
14 14
 class MarkdownExtraExtended_Parser extends MarkdownExtra_Parser
15 15
 {
16 16
 
17
-    # Tags that are always treated as block tags:
18
-    var $block_tags_re = 'figure|figcaption|p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
19
-
20
-    var $default_classes;
21
-
22
-    function __construct($default_classes = array())
23
-    {
24
-        $default_classes = $default_classes;
25
-
26
-        $this->block_gamut += array(
27
-            "doFencedFigures" => 7,
28
-        );
29
-
30
-        parent::__construct();
31
-    }
32
-
33
-    function transform($text)
34
-    {
35
-        $text = parent::transform($text);
36
-        return $text;
37
-    }
38
-
39
-    function doHardBreaks($text)
40
-    {
41
-        # Do hard breaks:
42
-        # EXTENDED: changed to allow breaks without two spaces and just one new line
43
-        # original code /* return preg_replace_callback('/ {2,}\n/', */
44
-        return preg_replace_callback(
45
-            '/ *\n/',
46
-            array(&$this, '_doHardBreaks_callback'),
47
-            $text
48
-        );
49
-    }
50
-
51
-    function doBlockQuotes($text)
52
-    {
53
-        $text = preg_replace_callback(
54
-            '/
17
+	# Tags that are always treated as block tags:
18
+	var $block_tags_re = 'figure|figcaption|p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
19
+
20
+	var $default_classes;
21
+
22
+	function __construct($default_classes = array())
23
+	{
24
+		$default_classes = $default_classes;
25
+
26
+		$this->block_gamut += array(
27
+			"doFencedFigures" => 7,
28
+		);
29
+
30
+		parent::__construct();
31
+	}
32
+
33
+	function transform($text)
34
+	{
35
+		$text = parent::transform($text);
36
+		return $text;
37
+	}
38
+
39
+	function doHardBreaks($text)
40
+	{
41
+		# Do hard breaks:
42
+		# EXTENDED: changed to allow breaks without two spaces and just one new line
43
+		# original code /* return preg_replace_callback('/ {2,}\n/', */
44
+		return preg_replace_callback(
45
+			'/ *\n/',
46
+			array(&$this, '_doHardBreaks_callback'),
47
+			$text
48
+		);
49
+	}
50
+
51
+	function doBlockQuotes($text)
52
+	{
53
+		$text = preg_replace_callback(
54
+			'/
55 55
 			(?>^[ ]*>[ ]?
56 56
 				(?:\((.+?)\))?
57 57
 				[ ]*(.+\n(?:.+\n)*)
58 58
 			)+
59 59
 			/xm',
60
-            array(&$this, '_doBlockQuotes_callback'),
61
-            $text
62
-        );
63
-
64
-        return $text;
65
-    }
66
-
67
-    function _doBlockQuotes_callback($matches)
68
-    {
69
-        $cite = $matches[1];
70
-        $bq   = '> ' . $matches[2];
71
-        # trim one level of quoting - trim whitespace-only lines
72
-        $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
73
-        $bq = $this->runBlockGamut($bq); # recurse
74
-
75
-        $bq = preg_replace('/^/m', "  ", $bq);
76
-        # These leading spaces cause problem with <pre> content,
77
-        # so we need to fix that:
78
-        $bq = preg_replace_callback(
79
-            '{(\s*<pre>.+?</pre>)}sx',
80
-            array(&$this, '_doBlockQuotes_callback2'),
81
-            $bq
82
-        );
83
-
84
-        $res = "<blockquote";
85
-        $res .= empty($cite) ? ">" : " cite=\"$cite\">";
86
-        $res .= "\n$bq\n</blockquote>";
87
-        return "\n" . $this->hashBlock($res) . "\n\n";
88
-    }
89
-
90
-    function doFencedCodeBlocks($text)
91
-    {
92
-        $less_than_tab = $this->tab_width;
93
-
94
-        $text = preg_replace_callback(
95
-            '{
60
+			array(&$this, '_doBlockQuotes_callback'),
61
+			$text
62
+		);
63
+
64
+		return $text;
65
+	}
66
+
67
+	function _doBlockQuotes_callback($matches)
68
+	{
69
+		$cite = $matches[1];
70
+		$bq   = '> ' . $matches[2];
71
+		# trim one level of quoting - trim whitespace-only lines
72
+		$bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
73
+		$bq = $this->runBlockGamut($bq); # recurse
74
+
75
+		$bq = preg_replace('/^/m', "  ", $bq);
76
+		# These leading spaces cause problem with <pre> content,
77
+		# so we need to fix that:
78
+		$bq = preg_replace_callback(
79
+			'{(\s*<pre>.+?</pre>)}sx',
80
+			array(&$this, '_doBlockQuotes_callback2'),
81
+			$bq
82
+		);
83
+
84
+		$res = "<blockquote";
85
+		$res .= empty($cite) ? ">" : " cite=\"$cite\">";
86
+		$res .= "\n$bq\n</blockquote>";
87
+		return "\n" . $this->hashBlock($res) . "\n\n";
88
+	}
89
+
90
+	function doFencedCodeBlocks($text)
91
+	{
92
+		$less_than_tab = $this->tab_width;
93
+
94
+		$text = preg_replace_callback(
95
+			'{
96 96
 				(?:\n|\A)
97 97
 				# 1: Opening marker
98 98
 				(
@@ -112,34 +112,34 @@  discard block
 block discarded – undo
112 112
 				# Closing marker.
113 113
 				\1 [ ]* \n
114 114
 			}xm',
115
-            array(&$this, '_doFencedCodeBlocks_callback'),
116
-            $text
117
-        );
118
-
119
-        return $text;
120
-    }
121
-
122
-    function _doFencedCodeBlocks_callback($matches)
123
-    {
124
-        $codeblock = $matches[4];
125
-        $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
126
-        $codeblock = preg_replace_callback(
127
-            '/^\n+/',
128
-            array(&$this, '_doFencedCodeBlocks_newlines'),
129
-            $codeblock
130
-        );
131
-        //$codeblock = "<pre><code>$codeblock</code></pre>";
132
-        //$cb = "<pre><code";
133
-        $cb = empty($matches[3]) ? "<pre><code" : "<pre class=\"linenums:$matches[3]\"><code";
134
-        $cb .= empty($matches[2]) ? ">" : " class=\"language-$matches[2]\">";
135
-        $cb .= "$codeblock</code></pre>";
136
-        return "\n\n" . $this->hashBlock($cb) . "\n\n";
137
-    }
138
-
139
-    function doFencedFigures($text)
140
-    {
141
-        $text = preg_replace_callback(
142
-            '{
115
+			array(&$this, '_doFencedCodeBlocks_callback'),
116
+			$text
117
+		);
118
+
119
+		return $text;
120
+	}
121
+
122
+	function _doFencedCodeBlocks_callback($matches)
123
+	{
124
+		$codeblock = $matches[4];
125
+		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
126
+		$codeblock = preg_replace_callback(
127
+			'/^\n+/',
128
+			array(&$this, '_doFencedCodeBlocks_newlines'),
129
+			$codeblock
130
+		);
131
+		//$codeblock = "<pre><code>$codeblock</code></pre>";
132
+		//$cb = "<pre><code";
133
+		$cb = empty($matches[3]) ? "<pre><code" : "<pre class=\"linenums:$matches[3]\"><code";
134
+		$cb .= empty($matches[2]) ? ">" : " class=\"language-$matches[2]\">";
135
+		$cb .= "$codeblock</code></pre>";
136
+		return "\n\n" . $this->hashBlock($cb) . "\n\n";
137
+	}
138
+
139
+	function doFencedFigures($text)
140
+	{
141
+		$text = preg_replace_callback(
142
+			'{
143 143
 			(?:\n|\A)
144 144
 			# 1: Opening marker
145 145
 			(
@@ -159,41 +159,41 @@  discard block
 block discarded – undo
159 159
 			# Closing marker.
160 160
 			\1 [ ]?(?:\[([^\]]+)\])?[ ]* \n
161 161
 		}xm',
162
-            array(&$this, '_doFencedFigures_callback'),
163
-            $text
164
-        );
165
-
166
-        return $text;
167
-    }
168
-
169
-    function _doFencedFigures_callback($matches)
170
-    {
171
-        # get figcaption
172
-        $topcaption    = empty($matches[2]) ? null : $this->runBlockGamut($matches[2]);
173
-        $bottomcaption = empty($matches[5]) ? null : $this->runBlockGamut($matches[5]);
174
-        $figure        = $matches[3];
175
-        $figure        = $this->runBlockGamut($figure); # recurse
176
-
177
-        $figure = preg_replace('/^/m', "  ", $figure);
178
-        # These leading spaces cause problem with <pre> content,
179
-        # so we need to fix that - reuse blockqoute code to handle this:
180
-        $figure = preg_replace_callback(
181
-            '{(\s*<pre>.+?</pre>)}sx',
182
-            array(&$this, '_doBlockQuotes_callback2'),
183
-            $figure
184
-        );
185
-
186
-        $res = "<figure>";
187
-        if (!empty($topcaption)) {
188
-            $res .= "\n<figcaption>$topcaption</figcaption>";
189
-        }
190
-        $res .= "\n$figure\n";
191
-        if (!empty($bottomcaption) && empty($topcaption)) {
192
-            $res .= "<figcaption>$bottomcaption</figcaption>";
193
-        }
194
-        $res .= "</figure>";
195
-        return "\n" . $this->hashBlock($res) . "\n\n";
196
-    }
162
+			array(&$this, '_doFencedFigures_callback'),
163
+			$text
164
+		);
165
+
166
+		return $text;
167
+	}
168
+
169
+	function _doFencedFigures_callback($matches)
170
+	{
171
+		# get figcaption
172
+		$topcaption    = empty($matches[2]) ? null : $this->runBlockGamut($matches[2]);
173
+		$bottomcaption = empty($matches[5]) ? null : $this->runBlockGamut($matches[5]);
174
+		$figure        = $matches[3];
175
+		$figure        = $this->runBlockGamut($figure); # recurse
176
+
177
+		$figure = preg_replace('/^/m', "  ", $figure);
178
+		# These leading spaces cause problem with <pre> content,
179
+		# so we need to fix that - reuse blockqoute code to handle this:
180
+		$figure = preg_replace_callback(
181
+			'{(\s*<pre>.+?</pre>)}sx',
182
+			array(&$this, '_doBlockQuotes_callback2'),
183
+			$figure
184
+		);
185
+
186
+		$res = "<figure>";
187
+		if (!empty($topcaption)) {
188
+			$res .= "\n<figcaption>$topcaption</figcaption>";
189
+		}
190
+		$res .= "\n$figure\n";
191
+		if (!empty($bottomcaption) && empty($topcaption)) {
192
+			$res .= "<figcaption>$bottomcaption</figcaption>";
193
+		}
194
+		$res .= "</figure>";
195
+		return "\n" . $this->hashBlock($res) . "\n\n";
196
+	}
197 197
 }
198 198
 
199 199
 ?>
Please login to merge, or discard this patch.
application/helpers/markdown_helper.php 1 patch
Indentation   +2725 added lines, -2725 removed lines patch added patch discarded remove patch
@@ -56,15 +56,15 @@  discard block
 block discarded – undo
56 56
 #
57 57
 # Initialize the parser and return the result of its transform method.
58 58
 #
59
-    # Setup static parser variable.
60
-    static $parser;
61
-    if (!isset($parser)) {
62
-        $parser_class = MARKDOWN_PARSER_CLASS;
63
-        $parser       = new $parser_class;
64
-    }
65
-
66
-    # Transform text using parser.
67
-    return $parser->transform($text);
59
+	# Setup static parser variable.
60
+	static $parser;
61
+	if (!isset($parser)) {
62
+		$parser_class = MARKDOWN_PARSER_CLASS;
63
+		$parser       = new $parser_class;
64
+	}
65
+
66
+	# Transform text using parser.
67
+	return $parser->transform($text);
68 68
 }
69 69
 
70 70
 ### WordPress Plugin Interface ###
@@ -80,120 +80,120 @@  discard block
 block discarded – undo
80 80
 */
81 81
 
82 82
 if (isset($wp_version)) {
83
-    # More details about how it works here:
84
-    # <http://michelf.ca/weblog/2005/wordpress-text-flow-vs-markdown/>
85
-
86
-    # Post content and excerpts
87
-    # - Remove WordPress paragraph generator.
88
-    # - Run Markdown on excerpt, then remove all tags.
89
-    # - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
90
-    if (MARKDOWN_WP_POSTS) {
91
-        remove_filter('the_content', 'wpautop');
92
-        remove_filter('the_content_rss', 'wpautop');
93
-        remove_filter('the_excerpt', 'wpautop');
94
-        add_filter('the_content', 'mdwp_MarkdownPost', 6);
95
-        add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
96
-        add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
97
-        add_filter('get_the_excerpt', 'trim', 7);
98
-        add_filter('the_excerpt', 'mdwp_add_p');
99
-        add_filter('the_excerpt_rss', 'mdwp_strip_p');
100
-
101
-        remove_filter('content_save_pre', 'balanceTags', 50);
102
-        remove_filter('excerpt_save_pre', 'balanceTags', 50);
103
-        add_filter('the_content', 'balanceTags', 50);
104
-        add_filter('get_the_excerpt', 'balanceTags', 9);
105
-    }
106
-
107
-    # Add a footnote id prefix to posts when inside a loop.
108
-    function mdwp_MarkdownPost($text)
109
-    {
110
-        static $parser;
111
-        if (!$parser) {
112
-            $parser_class = MARKDOWN_PARSER_CLASS;
113
-            $parser       = new $parser_class;
114
-        }
115
-        if (is_single() || is_page() || is_feed()) {
116
-            $parser->fn_id_prefix = "";
117
-        } else {
118
-            $parser->fn_id_prefix = get_the_ID() . ".";
119
-        }
120
-        return $parser->transform($text);
121
-    }
122
-
123
-    # Comments
124
-    # - Remove WordPress paragraph generator.
125
-    # - Remove WordPress auto-link generator.
126
-    # - Scramble important tags before passing them to the kses filter.
127
-    # - Run Markdown on excerpt then remove paragraph tags.
128
-    if (MARKDOWN_WP_COMMENTS) {
129
-        remove_filter('comment_text', 'wpautop', 30);
130
-        remove_filter('comment_text', 'make_clickable');
131
-        add_filter('pre_comment_content', 'Markdown', 6);
132
-        add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
133
-        add_filter('pre_comment_content', 'mdwp_show_tags', 12);
134
-        add_filter('get_comment_text', 'Markdown', 6);
135
-        add_filter('get_comment_excerpt', 'Markdown', 6);
136
-        add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
137
-
138
-        global $mdwp_hidden_tags, $mdwp_placeholders;
139
-        $mdwp_hidden_tags  = explode(
140
-            ' ',
141
-            '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>'
142
-        );
143
-        $mdwp_placeholders = explode(
144
-            ' ',
145
-            str_rot13(
146
-                'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR ' .
147
-                'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'
148
-            )
149
-        );
150
-    }
151
-
152
-    function mdwp_add_p($text)
153
-    {
154
-        if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
155
-            $text = '<p>' . $text . '</p>';
156
-            $text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
157
-        }
158
-        return $text;
159
-    }
160
-
161
-    function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
162
-
163
-    function mdwp_hide_tags($text)
164
-    {
165
-        global $mdwp_hidden_tags, $mdwp_placeholders;
166
-        return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
167
-    }
168
-
169
-    function mdwp_show_tags($text)
170
-    {
171
-        global $mdwp_hidden_tags, $mdwp_placeholders;
172
-        return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
173
-    }
83
+	# More details about how it works here:
84
+	# <http://michelf.ca/weblog/2005/wordpress-text-flow-vs-markdown/>
85
+
86
+	# Post content and excerpts
87
+	# - Remove WordPress paragraph generator.
88
+	# - Run Markdown on excerpt, then remove all tags.
89
+	# - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
90
+	if (MARKDOWN_WP_POSTS) {
91
+		remove_filter('the_content', 'wpautop');
92
+		remove_filter('the_content_rss', 'wpautop');
93
+		remove_filter('the_excerpt', 'wpautop');
94
+		add_filter('the_content', 'mdwp_MarkdownPost', 6);
95
+		add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
96
+		add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
97
+		add_filter('get_the_excerpt', 'trim', 7);
98
+		add_filter('the_excerpt', 'mdwp_add_p');
99
+		add_filter('the_excerpt_rss', 'mdwp_strip_p');
100
+
101
+		remove_filter('content_save_pre', 'balanceTags', 50);
102
+		remove_filter('excerpt_save_pre', 'balanceTags', 50);
103
+		add_filter('the_content', 'balanceTags', 50);
104
+		add_filter('get_the_excerpt', 'balanceTags', 9);
105
+	}
106
+
107
+	# Add a footnote id prefix to posts when inside a loop.
108
+	function mdwp_MarkdownPost($text)
109
+	{
110
+		static $parser;
111
+		if (!$parser) {
112
+			$parser_class = MARKDOWN_PARSER_CLASS;
113
+			$parser       = new $parser_class;
114
+		}
115
+		if (is_single() || is_page() || is_feed()) {
116
+			$parser->fn_id_prefix = "";
117
+		} else {
118
+			$parser->fn_id_prefix = get_the_ID() . ".";
119
+		}
120
+		return $parser->transform($text);
121
+	}
122
+
123
+	# Comments
124
+	# - Remove WordPress paragraph generator.
125
+	# - Remove WordPress auto-link generator.
126
+	# - Scramble important tags before passing them to the kses filter.
127
+	# - Run Markdown on excerpt then remove paragraph tags.
128
+	if (MARKDOWN_WP_COMMENTS) {
129
+		remove_filter('comment_text', 'wpautop', 30);
130
+		remove_filter('comment_text', 'make_clickable');
131
+		add_filter('pre_comment_content', 'Markdown', 6);
132
+		add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
133
+		add_filter('pre_comment_content', 'mdwp_show_tags', 12);
134
+		add_filter('get_comment_text', 'Markdown', 6);
135
+		add_filter('get_comment_excerpt', 'Markdown', 6);
136
+		add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
137
+
138
+		global $mdwp_hidden_tags, $mdwp_placeholders;
139
+		$mdwp_hidden_tags  = explode(
140
+			' ',
141
+			'<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>'
142
+		);
143
+		$mdwp_placeholders = explode(
144
+			' ',
145
+			str_rot13(
146
+				'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR ' .
147
+				'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'
148
+			)
149
+		);
150
+	}
151
+
152
+	function mdwp_add_p($text)
153
+	{
154
+		if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
155
+			$text = '<p>' . $text . '</p>';
156
+			$text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
157
+		}
158
+		return $text;
159
+	}
160
+
161
+	function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
162
+
163
+	function mdwp_hide_tags($text)
164
+	{
165
+		global $mdwp_hidden_tags, $mdwp_placeholders;
166
+		return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
167
+	}
168
+
169
+	function mdwp_show_tags($text)
170
+	{
171
+		global $mdwp_hidden_tags, $mdwp_placeholders;
172
+		return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
173
+	}
174 174
 }
175 175
 
176 176
 ### bBlog Plugin Info ###
177 177
 
178 178
 function identify_modifier_markdown()
179 179
 {
180
-    return array(
181
-        'name'        => 'markdown',
182
-        'type'        => 'modifier',
183
-        'nicename'    => 'PHP Markdown Extra',
184
-        'description' => 'A text-to-HTML conversion tool for web writers',
185
-        'authors'     => 'Michel Fortin and John Gruber',
186
-        'licence'     => 'GPL',
187
-        'version'     => MARKDOWNEXTRA_VERSION,
188
-        'help'        => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.ca/projects/php-markdown/">More...</a>',
189
-    );
180
+	return array(
181
+		'name'        => 'markdown',
182
+		'type'        => 'modifier',
183
+		'nicename'    => 'PHP Markdown Extra',
184
+		'description' => 'A text-to-HTML conversion tool for web writers',
185
+		'authors'     => 'Michel Fortin and John Gruber',
186
+		'licence'     => 'GPL',
187
+		'version'     => MARKDOWNEXTRA_VERSION,
188
+		'help'        => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.ca/projects/php-markdown/">More...</a>',
189
+	);
190 190
 }
191 191
 
192 192
 ### Smarty Modifier Interface ###
193 193
 
194 194
 function smarty_modifier_markdown($text)
195 195
 {
196
-    return Markdown($text);
196
+	return Markdown($text);
197 197
 }
198 198
 
199 199
 ### Textile Compatibility Mode ###
@@ -201,32 +201,32 @@  discard block
 block discarded – undo
201 201
 # Rename this file to "classTextile.php" and it can replace Textile everywhere.
202 202
 
203 203
 if (strcasecmp(substr(__FILE__, - 16), "classTextile.php") == 0) {
204
-    # Try to include PHP SmartyPants. Should be in the same directory.
205
-    @include_once 'smartypants.php';
206
-
207
-    # Fake Textile class. It calls Markdown instead.
208
-    class Textile
209
-    {
210
-        function TextileThis($text, $lite = '', $encode = '')
211
-        {
212
-            if ($lite == '' && $encode == '') {
213
-                $text = Markdown($text);
214
-            }
215
-            if (function_exists('SmartyPants')) {
216
-                $text = SmartyPants($text);
217
-            }
218
-            return $text;
219
-        }
220
-
221
-        # Fake restricted version: restrictions are not supported for now.
222
-        function TextileRestricted($text, $lite = '', $noimage = '')
223
-        {
224
-            return $this->TextileThis($text, $lite);
225
-        }
226
-
227
-        # Workaround to ensure compatibility with TextPattern 4.0.3.
228
-        function blockLite($text) { return $text; }
229
-    }
204
+	# Try to include PHP SmartyPants. Should be in the same directory.
205
+	@include_once 'smartypants.php';
206
+
207
+	# Fake Textile class. It calls Markdown instead.
208
+	class Textile
209
+	{
210
+		function TextileThis($text, $lite = '', $encode = '')
211
+		{
212
+			if ($lite == '' && $encode == '') {
213
+				$text = Markdown($text);
214
+			}
215
+			if (function_exists('SmartyPants')) {
216
+				$text = SmartyPants($text);
217
+			}
218
+			return $text;
219
+		}
220
+
221
+		# Fake restricted version: restrictions are not supported for now.
222
+		function TextileRestricted($text, $lite = '', $noimage = '')
223
+		{
224
+			return $this->TextileThis($text, $lite);
225
+		}
226
+
227
+		# Workaround to ensure compatibility with TextPattern 4.0.3.
228
+		function blockLite($text) { return $text; }
229
+	}
230 230
 }
231 231
 
232 232
 #
@@ -236,156 +236,156 @@  discard block
 block discarded – undo
236 236
 class Markdown_Parser
237 237
 {
238 238
 
239
-    ### Configuration Variables ###
239
+	### Configuration Variables ###
240 240
 
241
-    # Change to ">" for HTML output.
242
-    var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
241
+	# Change to ">" for HTML output.
242
+	var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
243 243
 
244
-    var $tab_width = MARKDOWN_TAB_WIDTH;
244
+	var $tab_width = MARKDOWN_TAB_WIDTH;
245 245
 
246
-    # Change to `true` to disallow markup or entities.
247
-    var $no_markup = false;
246
+	# Change to `true` to disallow markup or entities.
247
+	var $no_markup = false;
248 248
 
249
-    var $no_entities = false;
249
+	var $no_entities = false;
250 250
 
251
-    # Predefined urls and titles for reference links and images.
252
-    var $predef_urls = array();
251
+	# Predefined urls and titles for reference links and images.
252
+	var $predef_urls = array();
253 253
 
254
-    var $predef_titles = array();
254
+	var $predef_titles = array();
255 255
 
256
-    ### Parser Implementation ###
256
+	### Parser Implementation ###
257 257
 
258
-    # Regex to match balanced [brackets].
259
-    # Needed to insert a maximum bracked depth while converting to PHP.
260
-    var $nested_brackets_depth = 6;
258
+	# Regex to match balanced [brackets].
259
+	# Needed to insert a maximum bracked depth while converting to PHP.
260
+	var $nested_brackets_depth = 6;
261 261
 
262
-    var $nested_brackets_re;
262
+	var $nested_brackets_re;
263 263
 
264
-    var $nested_url_parenthesis_depth = 4;
264
+	var $nested_url_parenthesis_depth = 4;
265 265
 
266
-    var $nested_url_parenthesis_re;
266
+	var $nested_url_parenthesis_re;
267 267
 
268
-    # Table of hash values for escaped characters:
269
-    var $escape_chars = '\`*_{}[]()>#+-.!';
268
+	# Table of hash values for escaped characters:
269
+	var $escape_chars = '\`*_{}[]()>#+-.!';
270 270
 
271
-    var $escape_chars_re;
271
+	var $escape_chars_re;
272 272
 
273
-    function __construct()
274
-    {
275
-        #
276
-        # Constructor function. Initialize appropriate member variables.
277
-        #
278
-        $this->_initDetab();
279
-        $this->prepareItalicsAndBold();
273
+	function __construct()
274
+	{
275
+		#
276
+		# Constructor function. Initialize appropriate member variables.
277
+		#
278
+		$this->_initDetab();
279
+		$this->prepareItalicsAndBold();
280 280
 
281
-        $this->nested_brackets_re =
282
-            str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth) .
283
-            str_repeat('\])*', $this->nested_brackets_depth);
281
+		$this->nested_brackets_re =
282
+			str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth) .
283
+			str_repeat('\])*', $this->nested_brackets_depth);
284 284
 
285
-        $this->nested_url_parenthesis_re =
286
-            str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth) .
287
-            str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
285
+		$this->nested_url_parenthesis_re =
286
+			str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth) .
287
+			str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
288 288
 
289
-        $this->escape_chars_re = '[' . preg_quote($this->escape_chars) . ']';
289
+		$this->escape_chars_re = '[' . preg_quote($this->escape_chars) . ']';
290 290
 
291
-        # Sort document, block, and span gamut in ascendent priority order.
292
-        asort($this->document_gamut);
293
-        asort($this->block_gamut);
294
-        asort($this->span_gamut);
295
-    }
291
+		# Sort document, block, and span gamut in ascendent priority order.
292
+		asort($this->document_gamut);
293
+		asort($this->block_gamut);
294
+		asort($this->span_gamut);
295
+	}
296 296
 
297
-    # Internal hashes used during transformation.
298
-    var $urls = array();
297
+	# Internal hashes used during transformation.
298
+	var $urls = array();
299 299
 
300
-    var $titles = array();
300
+	var $titles = array();
301 301
 
302
-    var $html_hashes = array();
302
+	var $html_hashes = array();
303 303
 
304
-    # Status flag to avoid invalid nesting.
305
-    var $in_anchor = false;
304
+	# Status flag to avoid invalid nesting.
305
+	var $in_anchor = false;
306 306
 
307
-    function setup()
308
-    {
309
-        #
310
-        # Called before the transformation process starts to setup parser
311
-        # states.
312
-        #
313
-        # Clear global hashes.
314
-        $this->urls        = $this->predef_urls;
315
-        $this->titles      = $this->predef_titles;
316
-        $this->html_hashes = array();
307
+	function setup()
308
+	{
309
+		#
310
+		# Called before the transformation process starts to setup parser
311
+		# states.
312
+		#
313
+		# Clear global hashes.
314
+		$this->urls        = $this->predef_urls;
315
+		$this->titles      = $this->predef_titles;
316
+		$this->html_hashes = array();
317 317
 
318
-        $this->in_anchor = false;
319
-    }
318
+		$this->in_anchor = false;
319
+	}
320 320
 
321
-    function teardown()
322
-    {
323
-        #
324
-        # Called after the transformation process to clear any variable
325
-        # which may be taking up memory unnecessarly.
326
-        #
327
-        $this->urls        = array();
328
-        $this->titles      = array();
329
-        $this->html_hashes = array();
330
-    }
321
+	function teardown()
322
+	{
323
+		#
324
+		# Called after the transformation process to clear any variable
325
+		# which may be taking up memory unnecessarly.
326
+		#
327
+		$this->urls        = array();
328
+		$this->titles      = array();
329
+		$this->html_hashes = array();
330
+	}
331 331
 
332
-    function transform($text)
333
-    {
334
-        #
335
-        # Main function. Performs some preprocessing on the input text
336
-        # and pass it through the document gamut.
337
-        #
338
-        $this->setup();
332
+	function transform($text)
333
+	{
334
+		#
335
+		# Main function. Performs some preprocessing on the input text
336
+		# and pass it through the document gamut.
337
+		#
338
+		$this->setup();
339 339
 
340
-        # Remove UTF-8 BOM and marker character in input, if present.
341
-        $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
340
+		# Remove UTF-8 BOM and marker character in input, if present.
341
+		$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
342 342
 
343
-        # Standardize line endings:
344
-        #   DOS to Unix and Mac to Unix
345
-        $text = preg_replace('{\r\n?}', "\n", $text);
343
+		# Standardize line endings:
344
+		#   DOS to Unix and Mac to Unix
345
+		$text = preg_replace('{\r\n?}', "\n", $text);
346 346
 
347
-        # Make sure $text ends with a couple of newlines:
348
-        $text .= "\n\n";
349
-
350
-        # Convert all tabs to spaces.
351
-        $text = $this->detab($text);
352
-
353
-        # Turn block-level HTML blocks into hash entries
354
-        $text = $this->hashHTMLBlocks($text);
355
-
356
-        # Strip any lines consisting only of spaces and tabs.
357
-        # This makes subsequent regexen easier to write, because we can
358
-        # match consecutive blank lines with /\n+/ instead of something
359
-        # contorted like /[ ]*\n+/ .
360
-        $text = preg_replace('/^[ ]+$/m', '', $text);
361
-
362
-        # Run document gamut methods.
363
-        foreach ($this->document_gamut as $method => $priority) {
364
-            $text = $this->$method($text);
365
-        }
366
-
367
-        $this->teardown();
368
-
369
-        return $text . "\n";
370
-    }
371
-
372
-    var $document_gamut = array(
373
-        # Strip link definitions, store in hashes.
374
-        "stripLinkDefinitions" => 20,
375
-        "runBasicBlockGamut"   => 30,
376
-    );
377
-
378
-    function stripLinkDefinitions($text)
379
-    {
380
-        #
381
-        # Strips link definitions from text, stores the URLs and titles in
382
-        # hash references.
383
-        #
384
-        $less_than_tab = $this->tab_width - 1;
385
-
386
-        # Link defs are in the form: ^[id]: url "optional title"
387
-        $text = preg_replace_callback(
388
-            '{
347
+		# Make sure $text ends with a couple of newlines:
348
+		$text .= "\n\n";
349
+
350
+		# Convert all tabs to spaces.
351
+		$text = $this->detab($text);
352
+
353
+		# Turn block-level HTML blocks into hash entries
354
+		$text = $this->hashHTMLBlocks($text);
355
+
356
+		# Strip any lines consisting only of spaces and tabs.
357
+		# This makes subsequent regexen easier to write, because we can
358
+		# match consecutive blank lines with /\n+/ instead of something
359
+		# contorted like /[ ]*\n+/ .
360
+		$text = preg_replace('/^[ ]+$/m', '', $text);
361
+
362
+		# Run document gamut methods.
363
+		foreach ($this->document_gamut as $method => $priority) {
364
+			$text = $this->$method($text);
365
+		}
366
+
367
+		$this->teardown();
368
+
369
+		return $text . "\n";
370
+	}
371
+
372
+	var $document_gamut = array(
373
+		# Strip link definitions, store in hashes.
374
+		"stripLinkDefinitions" => 20,
375
+		"runBasicBlockGamut"   => 30,
376
+	);
377
+
378
+	function stripLinkDefinitions($text)
379
+	{
380
+		#
381
+		# Strips link definitions from text, stores the URLs and titles in
382
+		# hash references.
383
+		#
384
+		$less_than_tab = $this->tab_width - 1;
385
+
386
+		# Link defs are in the form: ^[id]: url "optional title"
387
+		$text = preg_replace_callback(
388
+			'{
389 389
 							^[ ]{0,' . $less_than_tab . '}\[(.+)\][ ]?:	# id = $1
390 390
 							  [ ]*
391 391
 							  \n?				# maybe *one* newline
@@ -407,51 +407,51 @@  discard block
 block discarded – undo
407 407
 							)?	# title is optional
408 408
 							(?:\n+|\Z)
409 409
 			}xm',
410
-            array(&$this, '_stripLinkDefinitions_callback'),
411
-            $text
412
-        );
413
-        return $text;
414
-    }
415
-
416
-    function _stripLinkDefinitions_callback($matches)
417
-    {
418
-        $link_id                = strtolower($matches[1]);
419
-        $url                    = $matches[2] == '' ? $matches[3] : $matches[2];
420
-        $this->urls[$link_id]   = $url;
421
-        $this->titles[$link_id] =& $matches[4];
422
-        return ''; # String that will replace the block
423
-    }
424
-
425
-    function hashHTMLBlocks($text)
426
-    {
427
-        if ($this->no_markup) {
428
-            return $text;
429
-        }
430
-
431
-        $less_than_tab = $this->tab_width - 1;
432
-
433
-        # Hashify HTML blocks:
434
-        # We only want to do this for block-level HTML tags, such as headers,
435
-        # lists, and tables. That's because we still want to wrap <p>s around
436
-        # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
437
-        # phrase emphasis, and spans. The list of tags we're looking for is
438
-        # hard-coded:
439
-        #
440
-        # *  List "a" is made of tags which can be both inline or block-level.
441
-        #    These will be treated block-level when the start tag is alone on
442
-        #    its line, otherwise they're not matched here and will be taken as
443
-        #    inline later.
444
-        # *  List "b" is made of tags which are always block-level;
445
-        #
446
-        $block_tags_a_re = 'ins|del';
447
-        $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|' .
448
-                           'script|noscript|form|fieldset|iframe|math|svg|' .
449
-                           'article|section|nav|aside|hgroup|header|footer|' .
450
-                           'figure';
451
-
452
-        # Regular expression for the content of a block tag.
453
-        $nested_tags_level = 4;
454
-        $attr              = '
410
+			array(&$this, '_stripLinkDefinitions_callback'),
411
+			$text
412
+		);
413
+		return $text;
414
+	}
415
+
416
+	function _stripLinkDefinitions_callback($matches)
417
+	{
418
+		$link_id                = strtolower($matches[1]);
419
+		$url                    = $matches[2] == '' ? $matches[3] : $matches[2];
420
+		$this->urls[$link_id]   = $url;
421
+		$this->titles[$link_id] =& $matches[4];
422
+		return ''; # String that will replace the block
423
+	}
424
+
425
+	function hashHTMLBlocks($text)
426
+	{
427
+		if ($this->no_markup) {
428
+			return $text;
429
+		}
430
+
431
+		$less_than_tab = $this->tab_width - 1;
432
+
433
+		# Hashify HTML blocks:
434
+		# We only want to do this for block-level HTML tags, such as headers,
435
+		# lists, and tables. That's because we still want to wrap <p>s around
436
+		# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
437
+		# phrase emphasis, and spans. The list of tags we're looking for is
438
+		# hard-coded:
439
+		#
440
+		# *  List "a" is made of tags which can be both inline or block-level.
441
+		#    These will be treated block-level when the start tag is alone on
442
+		#    its line, otherwise they're not matched here and will be taken as
443
+		#    inline later.
444
+		# *  List "b" is made of tags which are always block-level;
445
+		#
446
+		$block_tags_a_re = 'ins|del';
447
+		$block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|' .
448
+						   'script|noscript|form|fieldset|iframe|math|svg|' .
449
+						   'article|section|nav|aside|hgroup|header|footer|' .
450
+						   'figure';
451
+
452
+		# Regular expression for the content of a block tag.
453
+		$nested_tags_level = 4;
454
+		$attr              = '
455 455
 			(?>				# optional tag attributes
456 456
 			  \s			# starts with whitespace
457 457
 			  (?>
@@ -465,9 +465,9 @@  discard block
 block discarded – undo
465 465
 			  )*
466 466
 			)?
467 467
 			';
468
-        $content           =
469
-            str_repeat(
470
-                '
468
+		$content           =
469
+			str_repeat(
470
+				'
471 471
 				(?>
472 472
 				  [^<]+			# content without tag
473 473
 				|
@@ -477,34 +477,34 @@  discard block
 block discarded – undo
477 477
 					  />
478 478
 					|
479 479
 					  >',
480
-                $nested_tags_level
481
-            ) . # end of opening tag
482
-            '.*?' . # last level nested tag content
483
-            str_repeat(
484
-                '
480
+				$nested_tags_level
481
+			) . # end of opening tag
482
+			'.*?' . # last level nested tag content
483
+			str_repeat(
484
+				'
485 485
 					  </\2\s*>	# closing nested tag
486 486
 					)
487 487
 				  |
488 488
 					<(?!/\2\s*>	# other tags with a different name
489 489
 				  )
490 490
 				)*',
491
-                $nested_tags_level
492
-            );
493
-        $content2          = str_replace('\2', '\3', $content);
494
-
495
-        # First, look for nested blocks, e.g.:
496
-        # 	<div>
497
-        # 		<div>
498
-        # 		tags for inner block must be indented.
499
-        # 		</div>
500
-        # 	</div>
501
-        #
502
-        # The outermost tags must start at the left margin for this to match, and
503
-        # the inner nested divs must be indented.
504
-        # We need to do this before the next, more liberal match, because the next
505
-        # match will start at the first `<div>` and stop at the first `</div>`.
506
-        $text = preg_replace_callback(
507
-            '{(?>
491
+				$nested_tags_level
492
+			);
493
+		$content2          = str_replace('\2', '\3', $content);
494
+
495
+		# First, look for nested blocks, e.g.:
496
+		# 	<div>
497
+		# 		<div>
498
+		# 		tags for inner block must be indented.
499
+		# 		</div>
500
+		# 	</div>
501
+		#
502
+		# The outermost tags must start at the left margin for this to match, and
503
+		# the inner nested divs must be indented.
504
+		# We need to do this before the next, more liberal match, because the next
505
+		# match will start at the first `<div>` and stop at the first `</div>`.
506
+		$text = preg_replace_callback(
507
+			'{(?>
508 508
 			(?>
509 509
 				(?<=\n\n)		# Starting after a blank line
510 510
 				|				# or
@@ -565,100 +565,100 @@  discard block
 block discarded – undo
565 565
 
566 566
 			)
567 567
 			)}Sxmi',
568
-            array(&$this, '_hashHTMLBlocks_callback'),
569
-            $text
570
-        );
571
-
572
-        return $text;
573
-    }
574
-
575
-    function _hashHTMLBlocks_callback($matches)
576
-    {
577
-        $text = $matches[1];
578
-        $key  = $this->hashBlock($text);
579
-        return "\n\n$key\n\n";
580
-    }
581
-
582
-    function hashPart($text, $boundary = 'X')
583
-    {
584
-        #
585
-        # Called whenever a tag must be hashed when a function insert an atomic
586
-        # element in the text stream. Passing $text to through this function gives
587
-        # a unique text-token which will be reverted back when calling unhash.
588
-        #
589
-        # The $boundary argument specify what character should be used to surround
590
-        # the token. By convension, "B" is used for block elements that needs not
591
-        # to be wrapped into paragraph tags at the end, ":" is used for elements
592
-        # that are word separators and "X" is used in the general case.
593
-        #
594
-        # Swap back any tag hash found in $text so we do not have to `unhash`
595
-        # multiple times at the end.
596
-        $text = $this->unhash($text);
597
-
598
-        # Then hash the block.
599
-        static $i = 0;
600
-        $key                     = "$boundary\x1A" . ++ $i . $boundary;
601
-        $this->html_hashes[$key] = $text;
602
-        return $key; # String that will replace the tag.
603
-    }
604
-
605
-    function hashBlock($text)
606
-    {
607
-        #
608
-        # Shortcut function for hashPart with block-level boundaries.
609
-        #
610
-        return $this->hashPart($text, 'B');
611
-    }
612
-
613
-    var $block_gamut = array(
614
-        #
615
-        # These are all the transformations that form block-level
616
-        # tags like paragraphs, headers, and list items.
617
-        #
618
-        "doHeaders"         => 10,
619
-        "doHorizontalRules" => 20,
620
-        "doLists"           => 40,
621
-        "doCodeBlocks"      => 50,
622
-        "doBlockQuotes"     => 60,
623
-    );
624
-
625
-    function runBlockGamut($text)
626
-    {
627
-        #
628
-        # Run block gamut tranformations.
629
-        #
630
-        # We need to escape raw HTML in Markdown source before doing anything
631
-        # else. This need to be done for each block, and not only at the
632
-        # begining in the Markdown function since hashed blocks can be part of
633
-        # list items and could have been indented. Indented blocks would have
634
-        # been seen as a code block in a previous pass of hashHTMLBlocks.
635
-        $text = $this->hashHTMLBlocks($text);
636
-
637
-        return $this->runBasicBlockGamut($text);
638
-    }
639
-
640
-    function runBasicBlockGamut($text)
641
-    {
642
-        #
643
-        # Run block gamut tranformations, without hashing HTML blocks. This is
644
-        # useful when HTML blocks are known to be already hashed, like in the first
645
-        # whole-document pass.
646
-        #
647
-        foreach ($this->block_gamut as $method => $priority) {
648
-            $text = $this->$method($text);
649
-        }
650
-
651
-        # Finally form paragraph and restore hashed blocks.
652
-        $text = $this->formParagraphs($text);
653
-
654
-        return $text;
655
-    }
656
-
657
-    function doHorizontalRules($text)
658
-    {
659
-        # Do Horizontal Rules:
660
-        return preg_replace(
661
-            '{
568
+			array(&$this, '_hashHTMLBlocks_callback'),
569
+			$text
570
+		);
571
+
572
+		return $text;
573
+	}
574
+
575
+	function _hashHTMLBlocks_callback($matches)
576
+	{
577
+		$text = $matches[1];
578
+		$key  = $this->hashBlock($text);
579
+		return "\n\n$key\n\n";
580
+	}
581
+
582
+	function hashPart($text, $boundary = 'X')
583
+	{
584
+		#
585
+		# Called whenever a tag must be hashed when a function insert an atomic
586
+		# element in the text stream. Passing $text to through this function gives
587
+		# a unique text-token which will be reverted back when calling unhash.
588
+		#
589
+		# The $boundary argument specify what character should be used to surround
590
+		# the token. By convension, "B" is used for block elements that needs not
591
+		# to be wrapped into paragraph tags at the end, ":" is used for elements
592
+		# that are word separators and "X" is used in the general case.
593
+		#
594
+		# Swap back any tag hash found in $text so we do not have to `unhash`
595
+		# multiple times at the end.
596
+		$text = $this->unhash($text);
597
+
598
+		# Then hash the block.
599
+		static $i = 0;
600
+		$key                     = "$boundary\x1A" . ++ $i . $boundary;
601
+		$this->html_hashes[$key] = $text;
602
+		return $key; # String that will replace the tag.
603
+	}
604
+
605
+	function hashBlock($text)
606
+	{
607
+		#
608
+		# Shortcut function for hashPart with block-level boundaries.
609
+		#
610
+		return $this->hashPart($text, 'B');
611
+	}
612
+
613
+	var $block_gamut = array(
614
+		#
615
+		# These are all the transformations that form block-level
616
+		# tags like paragraphs, headers, and list items.
617
+		#
618
+		"doHeaders"         => 10,
619
+		"doHorizontalRules" => 20,
620
+		"doLists"           => 40,
621
+		"doCodeBlocks"      => 50,
622
+		"doBlockQuotes"     => 60,
623
+	);
624
+
625
+	function runBlockGamut($text)
626
+	{
627
+		#
628
+		# Run block gamut tranformations.
629
+		#
630
+		# We need to escape raw HTML in Markdown source before doing anything
631
+		# else. This need to be done for each block, and not only at the
632
+		# begining in the Markdown function since hashed blocks can be part of
633
+		# list items and could have been indented. Indented blocks would have
634
+		# been seen as a code block in a previous pass of hashHTMLBlocks.
635
+		$text = $this->hashHTMLBlocks($text);
636
+
637
+		return $this->runBasicBlockGamut($text);
638
+	}
639
+
640
+	function runBasicBlockGamut($text)
641
+	{
642
+		#
643
+		# Run block gamut tranformations, without hashing HTML blocks. This is
644
+		# useful when HTML blocks are known to be already hashed, like in the first
645
+		# whole-document pass.
646
+		#
647
+		foreach ($this->block_gamut as $method => $priority) {
648
+			$text = $this->$method($text);
649
+		}
650
+
651
+		# Finally form paragraph and restore hashed blocks.
652
+		$text = $this->formParagraphs($text);
653
+
654
+		return $text;
655
+	}
656
+
657
+	function doHorizontalRules($text)
658
+	{
659
+		# Do Horizontal Rules:
660
+		return preg_replace(
661
+			'{
662 662
 				^[ ]{0,3}	# Leading space
663 663
 				([-*_])		# $1: First marker
664 664
 				(?>			# Repeated marker group
@@ -668,74 +668,74 @@  discard block
 block discarded – undo
668 668
 				[ ]*		# Tailing spaces
669 669
 				$			# End of line.
670 670
 			}mx',
671
-            "\n" . $this->hashBlock("<hr$this->empty_element_suffix") . "\n",
672
-            $text
673
-        );
674
-    }
675
-
676
-    var $span_gamut = array(
677
-        #
678
-        # These are all the transformations that occur *within* block-level
679
-        # tags like paragraphs, headers, and list items.
680
-        #
681
-        # Process character escapes, code spans, and inline HTML
682
-        # in one shot.
683
-        "parseSpan"           => - 30,
684
-        # Process anchor and image tags. Images must come first,
685
-        # because ![foo][f] looks like an anchor.
686
-        "doImages"            => 10,
687
-        "doAnchors"           => 20,
688
-        # Make links out of things like `<http://example.com/>`
689
-        # Must come after doAnchors, because you can use < and >
690
-        # delimiters in inline links like [this](<url>).
691
-        "doAutoLinks"         => 30,
692
-        "encodeAmpsAndAngles" => 40,
693
-        "doItalicsAndBold"    => 50,
694
-        "doHardBreaks"        => 60,
695
-    );
696
-
697
-    function runSpanGamut($text)
698
-    {
699
-        #
700
-        # Run span gamut tranformations.
701
-        #
702
-        foreach ($this->span_gamut as $method => $priority) {
703
-            $text = $this->$method($text);
704
-        }
705
-
706
-        return $text;
707
-    }
708
-
709
-    function doHardBreaks($text)
710
-    {
711
-        # Do hard breaks:
712
-        return preg_replace_callback(
713
-            '/ {2,}\n/',
714
-            array(&$this, '_doHardBreaks_callback'),
715
-            $text
716
-        );
717
-    }
718
-
719
-    function _doHardBreaks_callback($matches)
720
-    {
721
-        return $this->hashPart("<br$this->empty_element_suffix\n");
722
-    }
723
-
724
-    function doAnchors($text)
725
-    {
726
-        #
727
-        # Turn Markdown link shortcuts into XHTML <a> tags.
728
-        #
729
-        if ($this->in_anchor) {
730
-            return $text;
731
-        }
732
-        $this->in_anchor = true;
733
-
734
-        #
735
-        # First, handle reference-style links: [link text] [id]
736
-        #
737
-        $text = preg_replace_callback(
738
-            '{
671
+			"\n" . $this->hashBlock("<hr$this->empty_element_suffix") . "\n",
672
+			$text
673
+		);
674
+	}
675
+
676
+	var $span_gamut = array(
677
+		#
678
+		# These are all the transformations that occur *within* block-level
679
+		# tags like paragraphs, headers, and list items.
680
+		#
681
+		# Process character escapes, code spans, and inline HTML
682
+		# in one shot.
683
+		"parseSpan"           => - 30,
684
+		# Process anchor and image tags. Images must come first,
685
+		# because ![foo][f] looks like an anchor.
686
+		"doImages"            => 10,
687
+		"doAnchors"           => 20,
688
+		# Make links out of things like `<http://example.com/>`
689
+		# Must come after doAnchors, because you can use < and >
690
+		# delimiters in inline links like [this](<url>).
691
+		"doAutoLinks"         => 30,
692
+		"encodeAmpsAndAngles" => 40,
693
+		"doItalicsAndBold"    => 50,
694
+		"doHardBreaks"        => 60,
695
+	);
696
+
697
+	function runSpanGamut($text)
698
+	{
699
+		#
700
+		# Run span gamut tranformations.
701
+		#
702
+		foreach ($this->span_gamut as $method => $priority) {
703
+			$text = $this->$method($text);
704
+		}
705
+
706
+		return $text;
707
+	}
708
+
709
+	function doHardBreaks($text)
710
+	{
711
+		# Do hard breaks:
712
+		return preg_replace_callback(
713
+			'/ {2,}\n/',
714
+			array(&$this, '_doHardBreaks_callback'),
715
+			$text
716
+		);
717
+	}
718
+
719
+	function _doHardBreaks_callback($matches)
720
+	{
721
+		return $this->hashPart("<br$this->empty_element_suffix\n");
722
+	}
723
+
724
+	function doAnchors($text)
725
+	{
726
+		#
727
+		# Turn Markdown link shortcuts into XHTML <a> tags.
728
+		#
729
+		if ($this->in_anchor) {
730
+			return $text;
731
+		}
732
+		$this->in_anchor = true;
733
+
734
+		#
735
+		# First, handle reference-style links: [link text] [id]
736
+		#
737
+		$text = preg_replace_callback(
738
+			'{
739 739
 			(					# wrap whole match in $1
740 740
 			  \[
741 741
 				(' . $this->nested_brackets_re . ')	# link text = $2
@@ -749,15 +749,15 @@  discard block
 block discarded – undo
749 749
 			  \]
750 750
 			)
751 751
 			}xs',
752
-            array(&$this, '_doAnchors_reference_callback'),
753
-            $text
754
-        );
755
-
756
-        #
757
-        # Next, inline-style links: [link text](url "optional title")
758
-        #
759
-        $text = preg_replace_callback(
760
-            '{
752
+			array(&$this, '_doAnchors_reference_callback'),
753
+			$text
754
+		);
755
+
756
+		#
757
+		# Next, inline-style links: [link text](url "optional title")
758
+		#
759
+		$text = preg_replace_callback(
760
+			'{
761 761
 			(				# wrap whole match in $1
762 762
 			  \[
763 763
 				(' . $this->nested_brackets_re . ')	# link text = $2
@@ -779,97 +779,97 @@  discard block
 block discarded – undo
779 779
 			  \)
780 780
 			)
781 781
 			}xs',
782
-            array(&$this, '_doAnchors_inline_callback'),
783
-            $text
784
-        );
785
-
786
-        #
787
-        # Last, handle reference-style shortcuts: [link text]
788
-        # These must come last in case you've also got [link text][1]
789
-        # or [link text](/foo)
790
-        #
791
-        $text = preg_replace_callback(
792
-            '{
782
+			array(&$this, '_doAnchors_inline_callback'),
783
+			$text
784
+		);
785
+
786
+		#
787
+		# Last, handle reference-style shortcuts: [link text]
788
+		# These must come last in case you've also got [link text][1]
789
+		# or [link text](/foo)
790
+		#
791
+		$text = preg_replace_callback(
792
+			'{
793 793
 			(					# wrap whole match in $1
794 794
 			  \[
795 795
 				([^\[\]]+)		# link text = $2; can\'t contain [ or ]
796 796
 			  \]
797 797
 			)
798 798
 			}xs',
799
-            array(&$this, '_doAnchors_reference_callback'),
800
-            $text
801
-        );
802
-
803
-        $this->in_anchor = false;
804
-        return $text;
805
-    }
806
-
807
-    function _doAnchors_reference_callback($matches)
808
-    {
809
-        $whole_match = $matches[1];
810
-        $link_text   = $matches[2];
811
-        $link_id     =& $matches[3];
812
-
813
-        if ($link_id == "") {
814
-            # for shortcut links like [this][] or [this].
815
-            $link_id = $link_text;
816
-        }
817
-
818
-        # lower-case and turn embedded newlines into spaces
819
-        $link_id = strtolower($link_id);
820
-        $link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
821
-
822
-        if (isset($this->urls[$link_id])) {
823
-            $url = $this->urls[$link_id];
824
-            $url = $this->encodeAttribute($url);
825
-
826
-            $result = "<a href=\"$url\"";
827
-            if (isset($this->titles[$link_id])) {
828
-                $title = $this->titles[$link_id];
829
-                $title = $this->encodeAttribute($title);
830
-                $result .= " title=\"$title\"";
831
-            }
832
-
833
-            $link_text = $this->runSpanGamut($link_text);
834
-            $result .= ">$link_text</a>";
835
-            $result = $this->hashPart($result);
836
-        } else {
837
-            $result = $whole_match;
838
-        }
839
-        return $result;
840
-    }
841
-
842
-    function _doAnchors_inline_callback($matches)
843
-    {
844
-        $whole_match = $matches[1];
845
-        $link_text   = $this->runSpanGamut($matches[2]);
846
-        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
847
-        $title       =& $matches[7];
848
-
849
-        $url = $this->encodeAttribute($url);
850
-
851
-        $result = "<a href=\"$url\"";
852
-        if (isset($title)) {
853
-            $title = $this->encodeAttribute($title);
854
-            $result .= " title=\"$title\"";
855
-        }
856
-
857
-        $link_text = $this->runSpanGamut($link_text);
858
-        $result .= ">$link_text</a>";
859
-
860
-        return $this->hashPart($result);
861
-    }
862
-
863
-    function doImages($text)
864
-    {
865
-        #
866
-        # Turn Markdown image shortcuts into <img> tags.
867
-        #
868
-        #
869
-        # First, handle reference-style labeled images: ![alt text][id]
870
-        #
871
-        $text = preg_replace_callback(
872
-            '{
799
+			array(&$this, '_doAnchors_reference_callback'),
800
+			$text
801
+		);
802
+
803
+		$this->in_anchor = false;
804
+		return $text;
805
+	}
806
+
807
+	function _doAnchors_reference_callback($matches)
808
+	{
809
+		$whole_match = $matches[1];
810
+		$link_text   = $matches[2];
811
+		$link_id     =& $matches[3];
812
+
813
+		if ($link_id == "") {
814
+			# for shortcut links like [this][] or [this].
815
+			$link_id = $link_text;
816
+		}
817
+
818
+		# lower-case and turn embedded newlines into spaces
819
+		$link_id = strtolower($link_id);
820
+		$link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
821
+
822
+		if (isset($this->urls[$link_id])) {
823
+			$url = $this->urls[$link_id];
824
+			$url = $this->encodeAttribute($url);
825
+
826
+			$result = "<a href=\"$url\"";
827
+			if (isset($this->titles[$link_id])) {
828
+				$title = $this->titles[$link_id];
829
+				$title = $this->encodeAttribute($title);
830
+				$result .= " title=\"$title\"";
831
+			}
832
+
833
+			$link_text = $this->runSpanGamut($link_text);
834
+			$result .= ">$link_text</a>";
835
+			$result = $this->hashPart($result);
836
+		} else {
837
+			$result = $whole_match;
838
+		}
839
+		return $result;
840
+	}
841
+
842
+	function _doAnchors_inline_callback($matches)
843
+	{
844
+		$whole_match = $matches[1];
845
+		$link_text   = $this->runSpanGamut($matches[2]);
846
+		$url         = $matches[3] == '' ? $matches[4] : $matches[3];
847
+		$title       =& $matches[7];
848
+
849
+		$url = $this->encodeAttribute($url);
850
+
851
+		$result = "<a href=\"$url\"";
852
+		if (isset($title)) {
853
+			$title = $this->encodeAttribute($title);
854
+			$result .= " title=\"$title\"";
855
+		}
856
+
857
+		$link_text = $this->runSpanGamut($link_text);
858
+		$result .= ">$link_text</a>";
859
+
860
+		return $this->hashPart($result);
861
+	}
862
+
863
+	function doImages($text)
864
+	{
865
+		#
866
+		# Turn Markdown image shortcuts into <img> tags.
867
+		#
868
+		#
869
+		# First, handle reference-style labeled images: ![alt text][id]
870
+		#
871
+		$text = preg_replace_callback(
872
+			'{
873 873
 			(				# wrap whole match in $1
874 874
 			  !\[
875 875
 				(' . $this->nested_brackets_re . ')		# alt text = $2
@@ -884,16 +884,16 @@  discard block
 block discarded – undo
884 884
 
885 885
 			)
886 886
 			}xs',
887
-            array(&$this, '_doImages_reference_callback'),
888
-            $text
889
-        );
890
-
891
-        #
892
-        # Next, handle inline images:  ![alt text](url "optional title")
893
-        # Don't forget: encode * and _
894
-        #
895
-        $text = preg_replace_callback(
896
-            '{
887
+			array(&$this, '_doImages_reference_callback'),
888
+			$text
889
+		);
890
+
891
+		#
892
+		# Next, handle inline images:  ![alt text](url "optional title")
893
+		# Don't forget: encode * and _
894
+		#
895
+		$text = preg_replace_callback(
896
+			'{
897 897
 			(				# wrap whole match in $1
898 898
 			  !\[
899 899
 				(' . $this->nested_brackets_re . ')		# alt text = $2
@@ -916,85 +916,85 @@  discard block
 block discarded – undo
916 916
 			  \)
917 917
 			)
918 918
 			}xs',
919
-            array(&$this, '_doImages_inline_callback'),
920
-            $text
921
-        );
922
-
923
-        return $text;
924
-    }
925
-
926
-    function _doImages_reference_callback($matches)
927
-    {
928
-        $whole_match = $matches[1];
929
-        $alt_text    = $matches[2];
930
-        $link_id     = strtolower($matches[3]);
931
-
932
-        if ($link_id == "") {
933
-            $link_id = strtolower($alt_text); # for shortcut links like ![this][].
934
-        }
935
-
936
-        $alt_text = $this->encodeAttribute($alt_text);
937
-        if (isset($this->urls[$link_id])) {
938
-            $url    = $this->encodeAttribute($this->urls[$link_id]);
939
-            $result = "<img src=\"$url\" alt=\"$alt_text\"";
940
-            if (isset($this->titles[$link_id])) {
941
-                $title = $this->titles[$link_id];
942
-                $title = $this->encodeAttribute($title);
943
-                $result .= " title=\"$title\"";
944
-            }
945
-            $result .= $this->empty_element_suffix;
946
-            $result = $this->hashPart($result);
947
-        } else {
948
-            # If there's no such link ID, leave intact:
949
-            $result = $whole_match;
950
-        }
951
-
952
-        return $result;
953
-    }
954
-
955
-    function _doImages_inline_callback($matches)
956
-    {
957
-        $whole_match = $matches[1];
958
-        $alt_text    = $matches[2];
959
-        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
960
-        $title       =& $matches[7];
961
-
962
-        $alt_text = $this->encodeAttribute($alt_text);
963
-        $url      = $this->encodeAttribute($url);
964
-        $result   = "<img src=\"$url\" alt=\"$alt_text\"";
965
-        if (isset($title)) {
966
-            $title = $this->encodeAttribute($title);
967
-            $result .= " title=\"$title\""; # $title already quoted
968
-        }
969
-        $result .= $this->empty_element_suffix;
970
-
971
-        return $this->hashPart($result);
972
-    }
973
-
974
-    function doHeaders($text)
975
-    {
976
-        # Setext-style headers:
977
-        #	  Header 1
978
-        #	  ========
979
-        #
980
-        #	  Header 2
981
-        #	  --------
982
-        #
983
-        $text = preg_replace_callback(
984
-            '{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
985
-            array(&$this, '_doHeaders_callback_setext'),
986
-            $text
987
-        );
988
-
989
-        # atx-style headers:
990
-        #	# Header 1
991
-        #	## Header 2
992
-        #	## Header 2 with closing hashes ##
993
-        #	...
994
-        #	###### Header 6
995
-        #
996
-        $text = preg_replace_callback(
997
-            '{
919
+			array(&$this, '_doImages_inline_callback'),
920
+			$text
921
+		);
922
+
923
+		return $text;
924
+	}
925
+
926
+	function _doImages_reference_callback($matches)
927
+	{
928
+		$whole_match = $matches[1];
929
+		$alt_text    = $matches[2];
930
+		$link_id     = strtolower($matches[3]);
931
+
932
+		if ($link_id == "") {
933
+			$link_id = strtolower($alt_text); # for shortcut links like ![this][].
934
+		}
935
+
936
+		$alt_text = $this->encodeAttribute($alt_text);
937
+		if (isset($this->urls[$link_id])) {
938
+			$url    = $this->encodeAttribute($this->urls[$link_id]);
939
+			$result = "<img src=\"$url\" alt=\"$alt_text\"";
940
+			if (isset($this->titles[$link_id])) {
941
+				$title = $this->titles[$link_id];
942
+				$title = $this->encodeAttribute($title);
943
+				$result .= " title=\"$title\"";
944
+			}
945
+			$result .= $this->empty_element_suffix;
946
+			$result = $this->hashPart($result);
947
+		} else {
948
+			# If there's no such link ID, leave intact:
949
+			$result = $whole_match;
950
+		}
951
+
952
+		return $result;
953
+	}
954
+
955
+	function _doImages_inline_callback($matches)
956
+	{
957
+		$whole_match = $matches[1];
958
+		$alt_text    = $matches[2];
959
+		$url         = $matches[3] == '' ? $matches[4] : $matches[3];
960
+		$title       =& $matches[7];
961
+
962
+		$alt_text = $this->encodeAttribute($alt_text);
963
+		$url      = $this->encodeAttribute($url);
964
+		$result   = "<img src=\"$url\" alt=\"$alt_text\"";
965
+		if (isset($title)) {
966
+			$title = $this->encodeAttribute($title);
967
+			$result .= " title=\"$title\""; # $title already quoted
968
+		}
969
+		$result .= $this->empty_element_suffix;
970
+
971
+		return $this->hashPart($result);
972
+	}
973
+
974
+	function doHeaders($text)
975
+	{
976
+		# Setext-style headers:
977
+		#	  Header 1
978
+		#	  ========
979
+		#
980
+		#	  Header 2
981
+		#	  --------
982
+		#
983
+		$text = preg_replace_callback(
984
+			'{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
985
+			array(&$this, '_doHeaders_callback_setext'),
986
+			$text
987
+		);
988
+
989
+		# atx-style headers:
990
+		#	# Header 1
991
+		#	## Header 2
992
+		#	## Header 2 with closing hashes ##
993
+		#	...
994
+		#	###### Header 6
995
+		#
996
+		$text = preg_replace_callback(
997
+			'{
998 998
 				^(\#{1,6})	# $1 = string of #\'s
999 999
 				[ ]*
1000 1000
 				(.+?)		# $2 = Header text
@@ -1002,52 +1002,52 @@  discard block
 block discarded – undo
1002 1002
 				\#*			# optional closing #\'s (not counted)
1003 1003
 				\n+
1004 1004
 			}xm',
1005
-            array(&$this, '_doHeaders_callback_atx'),
1006
-            $text
1007
-        );
1008
-
1009
-        return $text;
1010
-    }
1011
-
1012
-    function _doHeaders_callback_setext($matches)
1013
-    {
1014
-        # Terrible hack to check we haven't found an empty list item.
1015
-        if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) {
1016
-            return $matches[0];
1017
-        }
1018
-
1019
-        $level = $matches[2]{0} == '=' ? 1 : 2;
1020
-        $block = "<h$level>" . $this->runSpanGamut($matches[1]) . "</h$level>";
1021
-        return "\n" . $this->hashBlock($block) . "\n\n";
1022
-    }
1023
-
1024
-    function _doHeaders_callback_atx($matches)
1025
-    {
1026
-        $level = strlen($matches[1]);
1027
-        $block = "<h$level>" . $this->runSpanGamut($matches[2]) . "</h$level>";
1028
-        return "\n" . $this->hashBlock($block) . "\n\n";
1029
-    }
1030
-
1031
-    function doLists($text)
1032
-    {
1033
-        #
1034
-        # Form HTML ordered (numbered) and unordered (bulleted) lists.
1035
-        #
1036
-        $less_than_tab = $this->tab_width - 1;
1037
-
1038
-        # Re-usable patterns to match list item bullets and number markers:
1039
-        $marker_ul_re  = '[*+-]';
1040
-        $marker_ol_re  = '\d+[\.]';
1041
-        $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
1042
-
1043
-        $markers_relist = array(
1044
-            $marker_ul_re => $marker_ol_re,
1045
-            $marker_ol_re => $marker_ul_re,
1046
-        );
1047
-
1048
-        foreach ($markers_relist as $marker_re => $other_marker_re) {
1049
-            # Re-usable pattern to match any entirel ul or ol list:
1050
-            $whole_list_re = '
1005
+			array(&$this, '_doHeaders_callback_atx'),
1006
+			$text
1007
+		);
1008
+
1009
+		return $text;
1010
+	}
1011
+
1012
+	function _doHeaders_callback_setext($matches)
1013
+	{
1014
+		# Terrible hack to check we haven't found an empty list item.
1015
+		if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) {
1016
+			return $matches[0];
1017
+		}
1018
+
1019
+		$level = $matches[2]{0} == '=' ? 1 : 2;
1020
+		$block = "<h$level>" . $this->runSpanGamut($matches[1]) . "</h$level>";
1021
+		return "\n" . $this->hashBlock($block) . "\n\n";
1022
+	}
1023
+
1024
+	function _doHeaders_callback_atx($matches)
1025
+	{
1026
+		$level = strlen($matches[1]);
1027
+		$block = "<h$level>" . $this->runSpanGamut($matches[2]) . "</h$level>";
1028
+		return "\n" . $this->hashBlock($block) . "\n\n";
1029
+	}
1030
+
1031
+	function doLists($text)
1032
+	{
1033
+		#
1034
+		# Form HTML ordered (numbered) and unordered (bulleted) lists.
1035
+		#
1036
+		$less_than_tab = $this->tab_width - 1;
1037
+
1038
+		# Re-usable patterns to match list item bullets and number markers:
1039
+		$marker_ul_re  = '[*+-]';
1040
+		$marker_ol_re  = '\d+[\.]';
1041
+		$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
1042
+
1043
+		$markers_relist = array(
1044
+			$marker_ul_re => $marker_ol_re,
1045
+			$marker_ol_re => $marker_ul_re,
1046
+		);
1047
+
1048
+		foreach ($markers_relist as $marker_re => $other_marker_re) {
1049
+			# Re-usable pattern to match any entirel ul or ol list:
1050
+			$whole_list_re = '
1051 1051
 				(								# $1 = whole list
1052 1052
 				  (								# $2
1053 1053
 					([ ]{0,' . $less_than_tab . '})	# $3 = number of spaces
@@ -1074,88 +1074,88 @@  discard block
 block discarded – undo
1074 1074
 				)
1075 1075
 			'; // mx
1076 1076
 
1077
-            # We use a different prefix before nested lists than top-level lists.
1078
-            # See extended comment in _ProcessListItems().
1077
+			# We use a different prefix before nested lists than top-level lists.
1078
+			# See extended comment in _ProcessListItems().
1079 1079
 
1080
-            if ($this->list_level) {
1081
-                $text = preg_replace_callback(
1082
-                    '{
1080
+			if ($this->list_level) {
1081
+				$text = preg_replace_callback(
1082
+					'{
1083 1083
 						^
1084 1084
 						' . $whole_list_re . '
1085 1085
 					}mx',
1086
-                    array(&$this, '_doLists_callback'),
1087
-                    $text
1088
-                );
1089
-            } else {
1090
-                $text = preg_replace_callback(
1091
-                    '{
1086
+					array(&$this, '_doLists_callback'),
1087
+					$text
1088
+				);
1089
+			} else {
1090
+				$text = preg_replace_callback(
1091
+					'{
1092 1092
 						(?:(?<=\n)\n|\A\n?) # Must eat the newline
1093 1093
 						' . $whole_list_re . '
1094 1094
 					}mx',
1095
-                    array(&$this, '_doLists_callback'),
1096
-                    $text
1097
-                );
1098
-            }
1099
-        }
1100
-
1101
-        return $text;
1102
-    }
1103
-
1104
-    function _doLists_callback($matches)
1105
-    {
1106
-        # Re-usable patterns to match list item bullets and number markers:
1107
-        $marker_ul_re  = '[*+-]';
1108
-        $marker_ol_re  = '\d+[\.]';
1109
-        $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
1110
-
1111
-        $list      = $matches[1];
1112
-        $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
1113
-
1114
-        $marker_any_re = ($list_type == "ul" ? $marker_ul_re : $marker_ol_re);
1115
-
1116
-        $list .= "\n";
1117
-        $result = $this->processListItems($list, $marker_any_re);
1118
-
1119
-        $result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
1120
-        return "\n" . $result . "\n\n";
1121
-    }
1122
-
1123
-    var $list_level = 0;
1124
-
1125
-    function processListItems($list_str, $marker_any_re)
1126
-    {
1127
-        #
1128
-        #	Process the contents of a single ordered or unordered list, splitting it
1129
-        #	into individual list items.
1130
-        #
1131
-        # The $this->list_level global keeps track of when we're inside a list.
1132
-        # Each time we enter a list, we increment it; when we leave a list,
1133
-        # we decrement. If it's zero, we're not in a list anymore.
1134
-        #
1135
-        # We do this because when we're not inside a list, we want to treat
1136
-        # something like this:
1137
-        #
1138
-        #		I recommend upgrading to version
1139
-        #		8. Oops, now this line is treated
1140
-        #		as a sub-list.
1141
-        #
1142
-        # As a single paragraph, despite the fact that the second line starts
1143
-        # with a digit-period-space sequence.
1144
-        #
1145
-        # Whereas when we're inside a list (or sub-list), that line will be
1146
-        # treated as the start of a sub-list. What a kludge, huh? This is
1147
-        # an aspect of Markdown's syntax that's hard to parse perfectly
1148
-        # without resorting to mind-reading. Perhaps the solution is to
1149
-        # change the syntax rules such that sub-lists must start with a
1150
-        # starting cardinal number; e.g. "1." or "a.".
1151
-
1152
-        $this->list_level ++;
1153
-
1154
-        # trim trailing blank lines:
1155
-        $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
1156
-
1157
-        $list_str = preg_replace_callback(
1158
-            '{
1095
+					array(&$this, '_doLists_callback'),
1096
+					$text
1097
+				);
1098
+			}
1099
+		}
1100
+
1101
+		return $text;
1102
+	}
1103
+
1104
+	function _doLists_callback($matches)
1105
+	{
1106
+		# Re-usable patterns to match list item bullets and number markers:
1107
+		$marker_ul_re  = '[*+-]';
1108
+		$marker_ol_re  = '\d+[\.]';
1109
+		$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
1110
+
1111
+		$list      = $matches[1];
1112
+		$list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
1113
+
1114
+		$marker_any_re = ($list_type == "ul" ? $marker_ul_re : $marker_ol_re);
1115
+
1116
+		$list .= "\n";
1117
+		$result = $this->processListItems($list, $marker_any_re);
1118
+
1119
+		$result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
1120
+		return "\n" . $result . "\n\n";
1121
+	}
1122
+
1123
+	var $list_level = 0;
1124
+
1125
+	function processListItems($list_str, $marker_any_re)
1126
+	{
1127
+		#
1128
+		#	Process the contents of a single ordered or unordered list, splitting it
1129
+		#	into individual list items.
1130
+		#
1131
+		# The $this->list_level global keeps track of when we're inside a list.
1132
+		# Each time we enter a list, we increment it; when we leave a list,
1133
+		# we decrement. If it's zero, we're not in a list anymore.
1134
+		#
1135
+		# We do this because when we're not inside a list, we want to treat
1136
+		# something like this:
1137
+		#
1138
+		#		I recommend upgrading to version
1139
+		#		8. Oops, now this line is treated
1140
+		#		as a sub-list.
1141
+		#
1142
+		# As a single paragraph, despite the fact that the second line starts
1143
+		# with a digit-period-space sequence.
1144
+		#
1145
+		# Whereas when we're inside a list (or sub-list), that line will be
1146
+		# treated as the start of a sub-list. What a kludge, huh? This is
1147
+		# an aspect of Markdown's syntax that's hard to parse perfectly
1148
+		# without resorting to mind-reading. Perhaps the solution is to
1149
+		# change the syntax rules such that sub-lists must start with a
1150
+		# starting cardinal number; e.g. "1." or "a.".
1151
+
1152
+		$this->list_level ++;
1153
+
1154
+		# trim trailing blank lines:
1155
+		$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
1156
+
1157
+		$list_str = preg_replace_callback(
1158
+			'{
1159 1159
 			(\n)?							# leading line = $1
1160 1160
 			(^[ ]*)							# leading whitespace = $2
1161 1161
 			(' . $marker_any_re . '				# list marker and space = $3
@@ -1165,45 +1165,45 @@  discard block
 block discarded – undo
1165 1165
 			(?:(\n+(?=\n))|\n)				# tailing blank line = $5
1166 1166
 			(?= \n* (\z | \2 (' . $marker_any_re . ') (?:[ ]+|(?=\n))))
1167 1167
 			}xm',
1168
-            array(&$this, '_processListItems_callback'),
1169
-            $list_str
1170
-        );
1171
-
1172
-        $this->list_level --;
1173
-        return $list_str;
1174
-    }
1175
-
1176
-    function _processListItems_callback($matches)
1177
-    {
1178
-        $item               = $matches[4];
1179
-        $leading_line       =& $matches[1];
1180
-        $leading_space      =& $matches[2];
1181
-        $marker_space       = $matches[3];
1182
-        $tailing_blank_line =& $matches[5];
1183
-
1184
-        if ($leading_line || $tailing_blank_line ||
1185
-            preg_match('/\n{2,}/', $item)
1186
-        ) {
1187
-            # Replace marker with the appropriate whitespace indentation
1188
-            $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
1189
-            $item = $this->runBlockGamut($this->outdent($item) . "\n");
1190
-        } else {
1191
-            # Recursion for sub-lists:
1192
-            $item = $this->doLists($this->outdent($item));
1193
-            $item = preg_replace('/\n+$/', '', $item);
1194
-            $item = $this->runSpanGamut($item);
1195
-        }
1196
-
1197
-        return "<li>" . $item . "</li>\n";
1198
-    }
1199
-
1200
-    function doCodeBlocks($text)
1201
-    {
1202
-        #
1203
-        #	Process Markdown `<pre><code>` blocks.
1204
-        #
1205
-        $text = preg_replace_callback(
1206
-            '{
1168
+			array(&$this, '_processListItems_callback'),
1169
+			$list_str
1170
+		);
1171
+
1172
+		$this->list_level --;
1173
+		return $list_str;
1174
+	}
1175
+
1176
+	function _processListItems_callback($matches)
1177
+	{
1178
+		$item               = $matches[4];
1179
+		$leading_line       =& $matches[1];
1180
+		$leading_space      =& $matches[2];
1181
+		$marker_space       = $matches[3];
1182
+		$tailing_blank_line =& $matches[5];
1183
+
1184
+		if ($leading_line || $tailing_blank_line ||
1185
+			preg_match('/\n{2,}/', $item)
1186
+		) {
1187
+			# Replace marker with the appropriate whitespace indentation
1188
+			$item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
1189
+			$item = $this->runBlockGamut($this->outdent($item) . "\n");
1190
+		} else {
1191
+			# Recursion for sub-lists:
1192
+			$item = $this->doLists($this->outdent($item));
1193
+			$item = preg_replace('/\n+$/', '', $item);
1194
+			$item = $this->runSpanGamut($item);
1195
+		}
1196
+
1197
+		return "<li>" . $item . "</li>\n";
1198
+	}
1199
+
1200
+	function doCodeBlocks($text)
1201
+	{
1202
+		#
1203
+		#	Process Markdown `<pre><code>` blocks.
1204
+		#
1205
+		$text = preg_replace_callback(
1206
+			'{
1207 1207
 				(?:\n\n|\A\n?)
1208 1208
 				(	            # $1 = the code block -- one or more lines, starting with a space/tab
1209 1209
 				  (?>
@@ -1213,206 +1213,206 @@  discard block
 block discarded – undo
1213 1213
 				)
1214 1214
 				((?=^[ ]{0,' . $this->tab_width . '}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
1215 1215
 			}xm',
1216
-            array(&$this, '_doCodeBlocks_callback'),
1217
-            $text
1218
-        );
1219
-
1220
-        return $text;
1221
-    }
1222
-
1223
-    function _doCodeBlocks_callback($matches)
1224
-    {
1225
-        $codeblock = $matches[1];
1226
-
1227
-        $codeblock = $this->outdent($codeblock);
1228
-        $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
1229
-
1230
-        # trim leading newlines and trailing newlines
1231
-        $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
1232
-
1233
-        $codeblock = "<pre><code>$codeblock\n</code></pre>";
1234
-        return "\n\n" . $this->hashBlock($codeblock) . "\n\n";
1235
-    }
1236
-
1237
-    function makeCodeSpan($code)
1238
-    {
1239
-        #
1240
-        # Create a code span markup for $code. Called from handleSpanToken.
1241
-        #
1242
-        $code = htmlspecialchars(trim($code), ENT_NOQUOTES);
1243
-        return $this->hashPart("<code>$code</code>");
1244
-    }
1245
-
1246
-    var $em_relist = array(
1247
-        ''  => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![\.,:;]\s)',
1248
-        '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
1249
-        '_' => '(?<=\S|^)(?<!_)_(?!_)',
1250
-    );
1251
-
1252
-    var $strong_relist = array(
1253
-        ''   => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![\.,:;]\s)',
1254
-        '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
1255
-        '__' => '(?<=\S|^)(?<!_)__(?!_)',
1256
-    );
1257
-
1258
-    var $em_strong_relist = array(
1259
-        ''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![\.,:;]\s)',
1260
-        '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
1261
-        '___' => '(?<=\S|^)(?<!_)___(?!_)',
1262
-    );
1263
-
1264
-    var $em_strong_prepared_relist;
1265
-
1266
-    function prepareItalicsAndBold()
1267
-    {
1268
-        #
1269
-        # Prepare regular expressions for searching emphasis tokens in any
1270
-        # context.
1271
-        #
1272
-        foreach ($this->em_relist as $em => $em_re) {
1273
-            foreach ($this->strong_relist as $strong => $strong_re) {
1274
-                # Construct list of allowed token expressions.
1275
-                $token_relist = array();
1276
-                if (isset($this->em_strong_relist["$em$strong"])) {
1277
-                    $token_relist[] = $this->em_strong_relist["$em$strong"];
1278
-                }
1279
-                $token_relist[] = $em_re;
1280
-                $token_relist[] = $strong_re;
1281
-
1282
-                # Construct master expression from list.
1283
-                $token_re                                      = '{(' . implode('|', $token_relist) . ')}';
1284
-                $this->em_strong_prepared_relist["$em$strong"] = $token_re;
1285
-            }
1286
-        }
1287
-    }
1288
-
1289
-    function doItalicsAndBold($text)
1290
-    {
1291
-        $token_stack  = array('');
1292
-        $text_stack   = array('');
1293
-        $em           = '';
1294
-        $strong       = '';
1295
-        $tree_char_em = false;
1296
-
1297
-        while (1) {
1298
-            #
1299
-            # Get prepared regular expression for seraching emphasis tokens
1300
-            # in current context.
1301
-            #
1302
-            $token_re = $this->em_strong_prepared_relist["$em$strong"];
1303
-
1304
-            #
1305
-            # Each loop iteration search for the next emphasis token.
1306
-            # Each token is then passed to handleSpanToken.
1307
-            #
1308
-            $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
1309
-            $text_stack[0] .= $parts[0];
1310
-            $token =& $parts[1];
1311
-            $text  =& $parts[2];
1312
-
1313
-            if (empty($token)) {
1314
-                # Reached end of text span: empty stack without emitting.
1315
-                # any more emphasis.
1316
-                while ($token_stack[0]) {
1317
-                    $text_stack[1] .= array_shift($token_stack);
1318
-                    $text_stack[0] .= array_shift($text_stack);
1319
-                }
1320
-                break;
1321
-            }
1322
-
1323
-            $token_len = strlen($token);
1324
-            if ($tree_char_em) {
1325
-                # Reached closing marker while inside a three-char emphasis.
1326
-                if ($token_len == 3) {
1327
-                    # Three-char closing marker, close em and strong.
1328
-                    array_shift($token_stack);
1329
-                    $span = array_shift($text_stack);
1330
-                    $span = $this->runSpanGamut($span);
1331
-                    $span = "<strong><em>$span</em></strong>";
1332
-                    $text_stack[0] .= $this->hashPart($span);
1333
-                    $em     = '';
1334
-                    $strong = '';
1335
-                } else {
1336
-                    # Other closing marker: close one em or strong and
1337
-                    # change current token state to match the other
1338
-                    $token_stack[0] = str_repeat($token{0}, 3 - $token_len);
1339
-                    $tag            = $token_len == 2 ? "strong" : "em";
1340
-                    $span           = $text_stack[0];
1341
-                    $span           = $this->runSpanGamut($span);
1342
-                    $span           = "<$tag>$span</$tag>";
1343
-                    $text_stack[0]  = $this->hashPart($span);
1344
-                    $$tag           = ''; # $$tag stands for $em or $strong
1345
-                }
1346
-                $tree_char_em = false;
1347
-            } else if ($token_len == 3) {
1348
-                if ($em) {
1349
-                    # Reached closing marker for both em and strong.
1350
-                    # Closing strong marker:
1351
-                    for ($i = 0; $i < 2; ++ $i) {
1352
-                        $shifted_token = array_shift($token_stack);
1353
-                        $tag           = strlen($shifted_token) == 2 ? "strong" : "em";
1354
-                        $span          = array_shift($text_stack);
1355
-                        $span          = $this->runSpanGamut($span);
1356
-                        $span          = "<$tag>$span</$tag>";
1357
-                        $text_stack[0] .= $this->hashPart($span);
1358
-                        $$tag = ''; # $$tag stands for $em or $strong
1359
-                    }
1360
-                } else {
1361
-                    # Reached opening three-char emphasis marker. Push on token
1362
-                    # stack; will be handled by the special condition above.
1363
-                    $em     = $token{0};
1364
-                    $strong = "$em$em";
1365
-                    array_unshift($token_stack, $token);
1366
-                    array_unshift($text_stack, '');
1367
-                    $tree_char_em = true;
1368
-                }
1369
-            } else if ($token_len == 2) {
1370
-                if ($strong) {
1371
-                    # Unwind any dangling emphasis marker:
1372
-                    if (strlen($token_stack[0]) == 1) {
1373
-                        $text_stack[1] .= array_shift($token_stack);
1374
-                        $text_stack[0] .= array_shift($text_stack);
1375
-                    }
1376
-                    # Closing strong marker:
1377
-                    array_shift($token_stack);
1378
-                    $span = array_shift($text_stack);
1379
-                    $span = $this->runSpanGamut($span);
1380
-                    $span = "<strong>$span</strong>";
1381
-                    $text_stack[0] .= $this->hashPart($span);
1382
-                    $strong = '';
1383
-                } else {
1384
-                    array_unshift($token_stack, $token);
1385
-                    array_unshift($text_stack, '');
1386
-                    $strong = $token;
1387
-                }
1388
-            } else {
1389
-                # Here $token_len == 1
1390
-                if ($em) {
1391
-                    if (strlen($token_stack[0]) == 1) {
1392
-                        # Closing emphasis marker:
1393
-                        array_shift($token_stack);
1394
-                        $span = array_shift($text_stack);
1395
-                        $span = $this->runSpanGamut($span);
1396
-                        $span = "<em>$span</em>";
1397
-                        $text_stack[0] .= $this->hashPart($span);
1398
-                        $em = '';
1399
-                    } else {
1400
-                        $text_stack[0] .= $token;
1401
-                    }
1402
-                } else {
1403
-                    array_unshift($token_stack, $token);
1404
-                    array_unshift($text_stack, '');
1405
-                    $em = $token;
1406
-                }
1407
-            }
1408
-        }
1409
-        return $text_stack[0];
1410
-    }
1411
-
1412
-    function doBlockQuotes($text)
1413
-    {
1414
-        $text = preg_replace_callback(
1415
-            '/
1216
+			array(&$this, '_doCodeBlocks_callback'),
1217
+			$text
1218
+		);
1219
+
1220
+		return $text;
1221
+	}
1222
+
1223
+	function _doCodeBlocks_callback($matches)
1224
+	{
1225
+		$codeblock = $matches[1];
1226
+
1227
+		$codeblock = $this->outdent($codeblock);
1228
+		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
1229
+
1230
+		# trim leading newlines and trailing newlines
1231
+		$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
1232
+
1233
+		$codeblock = "<pre><code>$codeblock\n</code></pre>";
1234
+		return "\n\n" . $this->hashBlock($codeblock) . "\n\n";
1235
+	}
1236
+
1237
+	function makeCodeSpan($code)
1238
+	{
1239
+		#
1240
+		# Create a code span markup for $code. Called from handleSpanToken.
1241
+		#
1242
+		$code = htmlspecialchars(trim($code), ENT_NOQUOTES);
1243
+		return $this->hashPart("<code>$code</code>");
1244
+	}
1245
+
1246
+	var $em_relist = array(
1247
+		''  => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![\.,:;]\s)',
1248
+		'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
1249
+		'_' => '(?<=\S|^)(?<!_)_(?!_)',
1250
+	);
1251
+
1252
+	var $strong_relist = array(
1253
+		''   => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![\.,:;]\s)',
1254
+		'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
1255
+		'__' => '(?<=\S|^)(?<!_)__(?!_)',
1256
+	);
1257
+
1258
+	var $em_strong_relist = array(
1259
+		''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![\.,:;]\s)',
1260
+		'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
1261
+		'___' => '(?<=\S|^)(?<!_)___(?!_)',
1262
+	);
1263
+
1264
+	var $em_strong_prepared_relist;
1265
+
1266
+	function prepareItalicsAndBold()
1267
+	{
1268
+		#
1269
+		# Prepare regular expressions for searching emphasis tokens in any
1270
+		# context.
1271
+		#
1272
+		foreach ($this->em_relist as $em => $em_re) {
1273
+			foreach ($this->strong_relist as $strong => $strong_re) {
1274
+				# Construct list of allowed token expressions.
1275
+				$token_relist = array();
1276
+				if (isset($this->em_strong_relist["$em$strong"])) {
1277
+					$token_relist[] = $this->em_strong_relist["$em$strong"];
1278
+				}
1279
+				$token_relist[] = $em_re;
1280
+				$token_relist[] = $strong_re;
1281
+
1282
+				# Construct master expression from list.
1283
+				$token_re                                      = '{(' . implode('|', $token_relist) . ')}';
1284
+				$this->em_strong_prepared_relist["$em$strong"] = $token_re;
1285
+			}
1286
+		}
1287
+	}
1288
+
1289
+	function doItalicsAndBold($text)
1290
+	{
1291
+		$token_stack  = array('');
1292
+		$text_stack   = array('');
1293
+		$em           = '';
1294
+		$strong       = '';
1295
+		$tree_char_em = false;
1296
+
1297
+		while (1) {
1298
+			#
1299
+			# Get prepared regular expression for seraching emphasis tokens
1300
+			# in current context.
1301
+			#
1302
+			$token_re = $this->em_strong_prepared_relist["$em$strong"];
1303
+
1304
+			#
1305
+			# Each loop iteration search for the next emphasis token.
1306
+			# Each token is then passed to handleSpanToken.
1307
+			#
1308
+			$parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
1309
+			$text_stack[0] .= $parts[0];
1310
+			$token =& $parts[1];
1311
+			$text  =& $parts[2];
1312
+
1313
+			if (empty($token)) {
1314
+				# Reached end of text span: empty stack without emitting.
1315
+				# any more emphasis.
1316
+				while ($token_stack[0]) {
1317
+					$text_stack[1] .= array_shift($token_stack);
1318
+					$text_stack[0] .= array_shift($text_stack);
1319
+				}
1320
+				break;
1321
+			}
1322
+
1323
+			$token_len = strlen($token);
1324
+			if ($tree_char_em) {
1325
+				# Reached closing marker while inside a three-char emphasis.
1326
+				if ($token_len == 3) {
1327
+					# Three-char closing marker, close em and strong.
1328
+					array_shift($token_stack);
1329
+					$span = array_shift($text_stack);
1330
+					$span = $this->runSpanGamut($span);
1331
+					$span = "<strong><em>$span</em></strong>";
1332
+					$text_stack[0] .= $this->hashPart($span);
1333
+					$em     = '';
1334
+					$strong = '';
1335
+				} else {
1336
+					# Other closing marker: close one em or strong and
1337
+					# change current token state to match the other
1338
+					$token_stack[0] = str_repeat($token{0}, 3 - $token_len);
1339
+					$tag            = $token_len == 2 ? "strong" : "em";
1340
+					$span           = $text_stack[0];
1341
+					$span           = $this->runSpanGamut($span);
1342
+					$span           = "<$tag>$span</$tag>";
1343
+					$text_stack[0]  = $this->hashPart($span);
1344
+					$$tag           = ''; # $$tag stands for $em or $strong
1345
+				}
1346
+				$tree_char_em = false;
1347
+			} else if ($token_len == 3) {
1348
+				if ($em) {
1349
+					# Reached closing marker for both em and strong.
1350
+					# Closing strong marker:
1351
+					for ($i = 0; $i < 2; ++ $i) {
1352
+						$shifted_token = array_shift($token_stack);
1353
+						$tag           = strlen($shifted_token) == 2 ? "strong" : "em";
1354
+						$span          = array_shift($text_stack);
1355
+						$span          = $this->runSpanGamut($span);
1356
+						$span          = "<$tag>$span</$tag>";
1357
+						$text_stack[0] .= $this->hashPart($span);
1358
+						$$tag = ''; # $$tag stands for $em or $strong
1359
+					}
1360
+				} else {
1361
+					# Reached opening three-char emphasis marker. Push on token
1362
+					# stack; will be handled by the special condition above.
1363
+					$em     = $token{0};
1364
+					$strong = "$em$em";
1365
+					array_unshift($token_stack, $token);
1366
+					array_unshift($text_stack, '');
1367
+					$tree_char_em = true;
1368
+				}
1369
+			} else if ($token_len == 2) {
1370
+				if ($strong) {
1371
+					# Unwind any dangling emphasis marker:
1372
+					if (strlen($token_stack[0]) == 1) {
1373
+						$text_stack[1] .= array_shift($token_stack);
1374
+						$text_stack[0] .= array_shift($text_stack);
1375
+					}
1376
+					# Closing strong marker:
1377
+					array_shift($token_stack);
1378
+					$span = array_shift($text_stack);
1379
+					$span = $this->runSpanGamut($span);
1380
+					$span = "<strong>$span</strong>";
1381
+					$text_stack[0] .= $this->hashPart($span);
1382
+					$strong = '';
1383
+				} else {
1384
+					array_unshift($token_stack, $token);
1385
+					array_unshift($text_stack, '');
1386
+					$strong = $token;
1387
+				}
1388
+			} else {
1389
+				# Here $token_len == 1
1390
+				if ($em) {
1391
+					if (strlen($token_stack[0]) == 1) {
1392
+						# Closing emphasis marker:
1393
+						array_shift($token_stack);
1394
+						$span = array_shift($text_stack);
1395
+						$span = $this->runSpanGamut($span);
1396
+						$span = "<em>$span</em>";
1397
+						$text_stack[0] .= $this->hashPart($span);
1398
+						$em = '';
1399
+					} else {
1400
+						$text_stack[0] .= $token;
1401
+					}
1402
+				} else {
1403
+					array_unshift($token_stack, $token);
1404
+					array_unshift($text_stack, '');
1405
+					$em = $token;
1406
+				}
1407
+			}
1408
+		}
1409
+		return $text_stack[0];
1410
+	}
1411
+
1412
+	function doBlockQuotes($text)
1413
+	{
1414
+		$text = preg_replace_callback(
1415
+			'/
1416 1416
 			  (								# Wrap whole match in $1
1417 1417
 				(?>
1418 1418
 				  ^[ ]*>[ ]?			# ">" at the start of a line
@@ -1422,66 +1422,66 @@  discard block
 block discarded – undo
1422 1422
 				)+
1423 1423
 			  )
1424 1424
 			/xm',
1425
-            array(&$this, '_doBlockQuotes_callback'),
1426
-            $text
1427
-        );
1428
-
1429
-        return $text;
1430
-    }
1431
-
1432
-    function _doBlockQuotes_callback($matches)
1433
-    {
1434
-        $bq = $matches[1];
1435
-        # trim one level of quoting - trim whitespace-only lines
1436
-        $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
1437
-        $bq = $this->runBlockGamut($bq); # recurse
1438
-
1439
-        $bq = preg_replace('/^/m', "  ", $bq);
1440
-        # These leading spaces cause problem with <pre> content,
1441
-        # so we need to fix that:
1442
-        $bq = preg_replace_callback(
1443
-            '{(\s*<pre>.+?</pre>)}sx',
1444
-            array(&$this, '_doBlockQuotes_callback2'),
1445
-            $bq
1446
-        );
1447
-
1448
-        return "\n" . $this->hashBlock("<blockquote>\n$bq\n</blockquote>") . "\n\n";
1449
-    }
1450
-
1451
-    function _doBlockQuotes_callback2($matches)
1452
-    {
1453
-        $pre = $matches[1];
1454
-        $pre = preg_replace('/^  /m', '', $pre);
1455
-        return $pre;
1456
-    }
1457
-
1458
-    function formParagraphs($text)
1459
-    {
1460
-        #
1461
-        #	Params:
1462
-        #		$text - string to process with html <p> tags
1463
-        #
1464
-        # Strip leading and trailing lines:
1465
-        $text = preg_replace('/\A\n+|\n+\z/', '', $text);
1466
-
1467
-        $grafs = preg_split('/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY);
1468
-
1469
-        #
1470
-        # Wrap <p> tags and unhashify HTML blocks
1471
-        #
1472
-        foreach ($grafs as $key => $value) {
1473
-            if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
1474
-                # Is a paragraph.
1475
-                $value = $this->runSpanGamut($value);
1476
-                $value = preg_replace('/^([ ]*)/', "<p>", $value);
1477
-                $value .= "</p>";
1478
-                $grafs[$key] = $this->unhash($value);
1479
-            } else {
1480
-                # Is a block.
1481
-                # Modify elements of @grafs in-place...
1482
-                $graf  = $value;
1483
-                $block = $this->html_hashes[$graf];
1484
-                $graf  = $block;
1425
+			array(&$this, '_doBlockQuotes_callback'),
1426
+			$text
1427
+		);
1428
+
1429
+		return $text;
1430
+	}
1431
+
1432
+	function _doBlockQuotes_callback($matches)
1433
+	{
1434
+		$bq = $matches[1];
1435
+		# trim one level of quoting - trim whitespace-only lines
1436
+		$bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
1437
+		$bq = $this->runBlockGamut($bq); # recurse
1438
+
1439
+		$bq = preg_replace('/^/m', "  ", $bq);
1440
+		# These leading spaces cause problem with <pre> content,
1441
+		# so we need to fix that:
1442
+		$bq = preg_replace_callback(
1443
+			'{(\s*<pre>.+?</pre>)}sx',
1444
+			array(&$this, '_doBlockQuotes_callback2'),
1445
+			$bq
1446
+		);
1447
+
1448
+		return "\n" . $this->hashBlock("<blockquote>\n$bq\n</blockquote>") . "\n\n";
1449
+	}
1450
+
1451
+	function _doBlockQuotes_callback2($matches)
1452
+	{
1453
+		$pre = $matches[1];
1454
+		$pre = preg_replace('/^  /m', '', $pre);
1455
+		return $pre;
1456
+	}
1457
+
1458
+	function formParagraphs($text)
1459
+	{
1460
+		#
1461
+		#	Params:
1462
+		#		$text - string to process with html <p> tags
1463
+		#
1464
+		# Strip leading and trailing lines:
1465
+		$text = preg_replace('/\A\n+|\n+\z/', '', $text);
1466
+
1467
+		$grafs = preg_split('/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY);
1468
+
1469
+		#
1470
+		# Wrap <p> tags and unhashify HTML blocks
1471
+		#
1472
+		foreach ($grafs as $key => $value) {
1473
+			if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
1474
+				# Is a paragraph.
1475
+				$value = $this->runSpanGamut($value);
1476
+				$value = preg_replace('/^([ ]*)/', "<p>", $value);
1477
+				$value .= "</p>";
1478
+				$grafs[$key] = $this->unhash($value);
1479
+			} else {
1480
+				# Is a block.
1481
+				# Modify elements of @grafs in-place...
1482
+				$graf  = $value;
1483
+				$block = $this->html_hashes[$graf];
1484
+				$graf  = $block;
1485 1485
 //				if (preg_match('{
1486 1486
 //					\A
1487 1487
 //					(							# $1 = <div> tag
@@ -1517,59 +1517,59 @@  discard block
 block discarded – undo
1517 1517
 //
1518 1518
 //					$graf = $div_open . "\n" . $div_content . "\n" . $div_close;
1519 1519
 //				}
1520
-                $grafs[$key] = $graf;
1521
-            }
1522
-        }
1523
-
1524
-        return implode("\n\n", $grafs);
1525
-    }
1526
-
1527
-    function encodeAttribute($text)
1528
-    {
1529
-        #
1530
-        # Encode text for a double-quoted HTML attribute. This function
1531
-        # is *not* suitable for attributes enclosed in single quotes.
1532
-        #
1533
-        $text = $this->encodeAmpsAndAngles($text);
1534
-        $text = str_replace('"', '&quot;', $text);
1535
-        return $text;
1536
-    }
1537
-
1538
-    function encodeAmpsAndAngles($text)
1539
-    {
1540
-        #
1541
-        # Smart processing for ampersands and angle brackets that need to
1542
-        # be encoded. Valid character entities are left alone unless the
1543
-        # no-entities mode is set.
1544
-        #
1545
-        if ($this->no_entities) {
1546
-            $text = str_replace('&', '&amp;', $text);
1547
-        } else {
1548
-            # Ampersand-encoding based entirely on Nat Irons's Amputator
1549
-            # MT plugin: <http://bumppo.net/projects/amputator/>
1550
-            $text = preg_replace(
1551
-                '/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
1552
-                '&amp;',
1553
-                $text
1554
-            );;
1555
-        }
1556
-        # Encode remaining <'s
1557
-        $text = str_replace('<', '&lt;', $text);
1558
-
1559
-        return $text;
1560
-    }
1561
-
1562
-    function doAutoLinks($text)
1563
-    {
1564
-        $text = preg_replace_callback(
1565
-            '{<((https?|ftp|dict):[^\'">\s]+)>}i',
1566
-            array(&$this, '_doAutoLinks_url_callback'),
1567
-            $text
1568
-        );
1569
-
1570
-        # Email addresses: <[email protected]>
1571
-        $text = preg_replace_callback(
1572
-            '{
1520
+				$grafs[$key] = $graf;
1521
+			}
1522
+		}
1523
+
1524
+		return implode("\n\n", $grafs);
1525
+	}
1526
+
1527
+	function encodeAttribute($text)
1528
+	{
1529
+		#
1530
+		# Encode text for a double-quoted HTML attribute. This function
1531
+		# is *not* suitable for attributes enclosed in single quotes.
1532
+		#
1533
+		$text = $this->encodeAmpsAndAngles($text);
1534
+		$text = str_replace('"', '&quot;', $text);
1535
+		return $text;
1536
+	}
1537
+
1538
+	function encodeAmpsAndAngles($text)
1539
+	{
1540
+		#
1541
+		# Smart processing for ampersands and angle brackets that need to
1542
+		# be encoded. Valid character entities are left alone unless the
1543
+		# no-entities mode is set.
1544
+		#
1545
+		if ($this->no_entities) {
1546
+			$text = str_replace('&', '&amp;', $text);
1547
+		} else {
1548
+			# Ampersand-encoding based entirely on Nat Irons's Amputator
1549
+			# MT plugin: <http://bumppo.net/projects/amputator/>
1550
+			$text = preg_replace(
1551
+				'/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
1552
+				'&amp;',
1553
+				$text
1554
+			);;
1555
+		}
1556
+		# Encode remaining <'s
1557
+		$text = str_replace('<', '&lt;', $text);
1558
+
1559
+		return $text;
1560
+	}
1561
+
1562
+	function doAutoLinks($text)
1563
+	{
1564
+		$text = preg_replace_callback(
1565
+			'{<((https?|ftp|dict):[^\'">\s]+)>}i',
1566
+			array(&$this, '_doAutoLinks_url_callback'),
1567
+			$text
1568
+		);
1569
+
1570
+		# Email addresses: <[email protected]>
1571
+		$text = preg_replace_callback(
1572
+			'{
1573 1573
 			<
1574 1574
 			(?:mailto:)?
1575 1575
 			(
@@ -1587,81 +1587,81 @@  discard block
 block discarded – undo
1587 1587
 			)
1588 1588
 			>
1589 1589
 			}xi',
1590
-            array(&$this, '_doAutoLinks_email_callback'),
1591
-            $text
1592
-        );
1593
-
1594
-        return $text;
1595
-    }
1596
-
1597
-    function _doAutoLinks_url_callback($matches)
1598
-    {
1599
-        $url  = $this->encodeAttribute($matches[1]);
1600
-        $link = "<a href=\"$url\">$url</a>";
1601
-        return $this->hashPart($link);
1602
-    }
1603
-
1604
-    function _doAutoLinks_email_callback($matches)
1605
-    {
1606
-        $address = $matches[1];
1607
-        $link    = $this->encodeEmailAddress($address);
1608
-        return $this->hashPart($link);
1609
-    }
1610
-
1611
-    function encodeEmailAddress($addr)
1612
-    {
1613
-        #
1614
-        #	Input: an email address, e.g. "[email protected]"
1615
-        #
1616
-        #	Output: the email address as a mailto link, with each character
1617
-        #		of the address encoded as either a decimal or hex entity, in
1618
-        #		the hopes of foiling most address harvesting spam bots. E.g.:
1619
-        #
1620
-        #	  <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
1621
-        #        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
1622
-        #        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
1623
-        #        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
1624
-        #
1625
-        #	Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
1626
-        #   With some optimizations by Milian Wolff.
1627
-        #
1628
-        $addr  = "mailto:" . $addr;
1629
-        $chars = preg_split('/(?<!^)(?!$)/', $addr);
1630
-        $seed  = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
1631
-
1632
-        foreach ($chars as $key => $char) {
1633
-            $ord = ord($char);
1634
-            # Ignore non-ascii chars.
1635
-            if ($ord < 128) {
1636
-                $r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
1637
-                # roughly 10% raw, 45% hex, 45% dec
1638
-                # '@' *must* be encoded. I insist.
1639
-                if ($r > 90 && $char != '@') /* do nothing */ {
1640
-                    ;
1641
-                } else if ($r < 45) {
1642
-                    $chars[$key] = '&#x' . dechex($ord) . ';';
1643
-                } else {
1644
-                    $chars[$key] = '&#' . $ord . ';';
1645
-                }
1646
-            }
1647
-        }
1648
-
1649
-        $addr = implode('', $chars);
1650
-        $text = implode('', array_slice($chars, 7)); # text without `mailto:`
1651
-        $addr = "<a href=\"$addr\">$text</a>";
1652
-
1653
-        return $addr;
1654
-    }
1655
-
1656
-    function parseSpan($str)
1657
-    {
1658
-        #
1659
-        # Take the string $str and parse it into tokens, hashing embeded HTML,
1660
-        # escaped characters and handling code spans.
1661
-        #
1662
-        $output = '';
1663
-
1664
-        $span_re = '{
1590
+			array(&$this, '_doAutoLinks_email_callback'),
1591
+			$text
1592
+		);
1593
+
1594
+		return $text;
1595
+	}
1596
+
1597
+	function _doAutoLinks_url_callback($matches)
1598
+	{
1599
+		$url  = $this->encodeAttribute($matches[1]);
1600
+		$link = "<a href=\"$url\">$url</a>";
1601
+		return $this->hashPart($link);
1602
+	}
1603
+
1604
+	function _doAutoLinks_email_callback($matches)
1605
+	{
1606
+		$address = $matches[1];
1607
+		$link    = $this->encodeEmailAddress($address);
1608
+		return $this->hashPart($link);
1609
+	}
1610
+
1611
+	function encodeEmailAddress($addr)
1612
+	{
1613
+		#
1614
+		#	Input: an email address, e.g. "[email protected]"
1615
+		#
1616
+		#	Output: the email address as a mailto link, with each character
1617
+		#		of the address encoded as either a decimal or hex entity, in
1618
+		#		the hopes of foiling most address harvesting spam bots. E.g.:
1619
+		#
1620
+		#	  <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
1621
+		#        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
1622
+		#        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
1623
+		#        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
1624
+		#
1625
+		#	Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
1626
+		#   With some optimizations by Milian Wolff.
1627
+		#
1628
+		$addr  = "mailto:" . $addr;
1629
+		$chars = preg_split('/(?<!^)(?!$)/', $addr);
1630
+		$seed  = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
1631
+
1632
+		foreach ($chars as $key => $char) {
1633
+			$ord = ord($char);
1634
+			# Ignore non-ascii chars.
1635
+			if ($ord < 128) {
1636
+				$r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
1637
+				# roughly 10% raw, 45% hex, 45% dec
1638
+				# '@' *must* be encoded. I insist.
1639
+				if ($r > 90 && $char != '@') /* do nothing */ {
1640
+					;
1641
+				} else if ($r < 45) {
1642
+					$chars[$key] = '&#x' . dechex($ord) . ';';
1643
+				} else {
1644
+					$chars[$key] = '&#' . $ord . ';';
1645
+				}
1646
+			}
1647
+		}
1648
+
1649
+		$addr = implode('', $chars);
1650
+		$text = implode('', array_slice($chars, 7)); # text without `mailto:`
1651
+		$addr = "<a href=\"$addr\">$text</a>";
1652
+
1653
+		return $addr;
1654
+	}
1655
+
1656
+	function parseSpan($str)
1657
+	{
1658
+		#
1659
+		# Take the string $str and parse it into tokens, hashing embeded HTML,
1660
+		# escaped characters and handling code spans.
1661
+		#
1662
+		$output = '';
1663
+
1664
+		$span_re = '{
1665 1665
 				(
1666 1666
 					\\\\' . $this->escape_chars_re . '
1667 1667
 				|
@@ -1687,142 +1687,142 @@  discard block
 block discarded – undo
1687 1687
 				)
1688 1688
 				}xs';
1689 1689
 
1690
-        while (1) {
1691
-            #
1692
-            # Each loop iteration seach for either the next tag, the next
1693
-            # openning code span marker, or the next escaped character.
1694
-            # Each token is then passed to handleSpanToken.
1695
-            #
1696
-            $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
1697
-
1698
-            # Create token from text preceding tag.
1699
-            if ($parts[0] != "") {
1700
-                $output .= $parts[0];
1701
-            }
1702
-
1703
-            # Check if we reach the end.
1704
-            if (isset($parts[1])) {
1705
-                $output .= $this->handleSpanToken($parts[1], $parts[2]);
1706
-                $str = $parts[2];
1707
-            } else {
1708
-                break;
1709
-            }
1710
-        }
1711
-
1712
-        return $output;
1713
-    }
1714
-
1715
-    function handleSpanToken($token, &$str)
1716
-    {
1717
-        #
1718
-        # Handle $token provided by parseSpan by determining its nature and
1719
-        # returning the corresponding value that should replace it.
1720
-        #
1721
-        switch ($token{0}) {
1722
-            case "\\":
1723
-                return $this->hashPart("&#" . ord($token{1}) . ";");
1724
-            case "`":
1725
-                # Search for end marker in remaining text.
1726
-                if (preg_match(
1727
-                    '/^(.*?[^`])' . preg_quote($token) . '(?!`)(.*)$/sm',
1728
-                    $str,
1729
-                    $matches
1730
-                )) {
1731
-                    $str      = $matches[2];
1732
-                    $codespan = $this->makeCodeSpan($matches[1]);
1733
-                    return $this->hashPart($codespan);
1734
-                }
1735
-                return $token; // return as text since no ending marker found.
1736
-            default:
1737
-                return $this->hashPart($token);
1738
-        }
1739
-    }
1740
-
1741
-    function outdent($text)
1742
-    {
1743
-        #
1744
-        # Remove one level of line-leading tabs or spaces
1745
-        #
1746
-        return preg_replace('/^(\t|[ ]{1,' . $this->tab_width . '})/m', '', $text);
1747
-    }
1748
-
1749
-
1750
-    # String length function for detab. `_initDetab` will create a function to
1751
-    # hanlde UTF-8 if the default function does not exist.
1752
-    var $utf8_strlen = 'mb_strlen';
1753
-
1754
-    function detab($text)
1755
-    {
1756
-        #
1757
-        # Replace tabs with the appropriate amount of space.
1758
-        #
1759
-        # For each line we separate the line in blocks delemited by
1760
-        # tab characters. Then we reconstruct every line by adding the
1761
-        # appropriate number of space between each blocks.
1762
-
1763
-        $text = preg_replace_callback(
1764
-            '/^.*\t.*$/m',
1765
-            array(&$this, '_detab_callback'),
1766
-            $text
1767
-        );
1768
-
1769
-        return $text;
1770
-    }
1771
-
1772
-    function _detab_callback($matches)
1773
-    {
1774
-        $line   = $matches[0];
1775
-        $strlen = $this->utf8_strlen; # strlen function for UTF-8.
1776
-
1777
-        # Split in blocks.
1778
-        $blocks = explode("\t", $line);
1779
-        # Add each blocks to the line.
1780
-        $line = $blocks[0];
1781
-        unset($blocks[0]); # Do not add first block twice.
1782
-        foreach ($blocks as $block) {
1783
-            # Calculate amount of space, insert spaces, insert block.
1784
-            $amount = $this->tab_width -
1785
-                      $strlen($line, 'UTF-8') % $this->tab_width;
1786
-            $line .= str_repeat(" ", $amount) . $block;
1787
-        }
1788
-        return $line;
1789
-    }
1790
-
1791
-    function _initDetab()
1792
-    {
1793
-        #
1794
-        # Check for the availability of the function in the `utf8_strlen` property
1795
-        # (initially `mb_strlen`). If the function is not available, create a
1796
-        # function that will loosely count the number of UTF-8 characters with a
1797
-        # regular expression.
1798
-        #
1799
-        if (function_exists($this->utf8_strlen)) {
1800
-            return;
1801
-        }
1802
-        $this->utf8_strlen = create_function(
1803
-            '$text',
1804
-            'return preg_match_all(
1690
+		while (1) {
1691
+			#
1692
+			# Each loop iteration seach for either the next tag, the next
1693
+			# openning code span marker, or the next escaped character.
1694
+			# Each token is then passed to handleSpanToken.
1695
+			#
1696
+			$parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
1697
+
1698
+			# Create token from text preceding tag.
1699
+			if ($parts[0] != "") {
1700
+				$output .= $parts[0];
1701
+			}
1702
+
1703
+			# Check if we reach the end.
1704
+			if (isset($parts[1])) {
1705
+				$output .= $this->handleSpanToken($parts[1], $parts[2]);
1706
+				$str = $parts[2];
1707
+			} else {
1708
+				break;
1709
+			}
1710
+		}
1711
+
1712
+		return $output;
1713
+	}
1714
+
1715
+	function handleSpanToken($token, &$str)
1716
+	{
1717
+		#
1718
+		# Handle $token provided by parseSpan by determining its nature and
1719
+		# returning the corresponding value that should replace it.
1720
+		#
1721
+		switch ($token{0}) {
1722
+			case "\\":
1723
+				return $this->hashPart("&#" . ord($token{1}) . ";");
1724
+			case "`":
1725
+				# Search for end marker in remaining text.
1726
+				if (preg_match(
1727
+					'/^(.*?[^`])' . preg_quote($token) . '(?!`)(.*)$/sm',
1728
+					$str,
1729
+					$matches
1730
+				)) {
1731
+					$str      = $matches[2];
1732
+					$codespan = $this->makeCodeSpan($matches[1]);
1733
+					return $this->hashPart($codespan);
1734
+				}
1735
+				return $token; // return as text since no ending marker found.
1736
+			default:
1737
+				return $this->hashPart($token);
1738
+		}
1739
+	}
1740
+
1741
+	function outdent($text)
1742
+	{
1743
+		#
1744
+		# Remove one level of line-leading tabs or spaces
1745
+		#
1746
+		return preg_replace('/^(\t|[ ]{1,' . $this->tab_width . '})/m', '', $text);
1747
+	}
1748
+
1749
+
1750
+	# String length function for detab. `_initDetab` will create a function to
1751
+	# hanlde UTF-8 if the default function does not exist.
1752
+	var $utf8_strlen = 'mb_strlen';
1753
+
1754
+	function detab($text)
1755
+	{
1756
+		#
1757
+		# Replace tabs with the appropriate amount of space.
1758
+		#
1759
+		# For each line we separate the line in blocks delemited by
1760
+		# tab characters. Then we reconstruct every line by adding the
1761
+		# appropriate number of space between each blocks.
1762
+
1763
+		$text = preg_replace_callback(
1764
+			'/^.*\t.*$/m',
1765
+			array(&$this, '_detab_callback'),
1766
+			$text
1767
+		);
1768
+
1769
+		return $text;
1770
+	}
1771
+
1772
+	function _detab_callback($matches)
1773
+	{
1774
+		$line   = $matches[0];
1775
+		$strlen = $this->utf8_strlen; # strlen function for UTF-8.
1776
+
1777
+		# Split in blocks.
1778
+		$blocks = explode("\t", $line);
1779
+		# Add each blocks to the line.
1780
+		$line = $blocks[0];
1781
+		unset($blocks[0]); # Do not add first block twice.
1782
+		foreach ($blocks as $block) {
1783
+			# Calculate amount of space, insert spaces, insert block.
1784
+			$amount = $this->tab_width -
1785
+					  $strlen($line, 'UTF-8') % $this->tab_width;
1786
+			$line .= str_repeat(" ", $amount) . $block;
1787
+		}
1788
+		return $line;
1789
+	}
1790
+
1791
+	function _initDetab()
1792
+	{
1793
+		#
1794
+		# Check for the availability of the function in the `utf8_strlen` property
1795
+		# (initially `mb_strlen`). If the function is not available, create a
1796
+		# function that will loosely count the number of UTF-8 characters with a
1797
+		# regular expression.
1798
+		#
1799
+		if (function_exists($this->utf8_strlen)) {
1800
+			return;
1801
+		}
1802
+		$this->utf8_strlen = create_function(
1803
+			'$text',
1804
+			'return preg_match_all(
1805 1805
 			"/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
1806 1806
 			$text, $m);'
1807
-        );
1808
-    }
1809
-
1810
-    function unhash($text)
1811
-    {
1812
-        #
1813
-        # Swap back in all the tags hashed by _HashHTMLBlocks.
1814
-        #
1815
-        return preg_replace_callback(
1816
-            '/(.)\x1A[0-9]+\1/',
1817
-            array(&$this, '_unhash_callback'),
1818
-            $text
1819
-        );
1820
-    }
1821
-
1822
-    function _unhash_callback($matches)
1823
-    {
1824
-        return $this->html_hashes[$matches[0]];
1825
-    }
1807
+		);
1808
+	}
1809
+
1810
+	function unhash($text)
1811
+	{
1812
+		#
1813
+		# Swap back in all the tags hashed by _HashHTMLBlocks.
1814
+		#
1815
+		return preg_replace_callback(
1816
+			'/(.)\x1A[0-9]+\1/',
1817
+			array(&$this, '_unhash_callback'),
1818
+			$text
1819
+		);
1820
+	}
1821
+
1822
+	function _unhash_callback($matches)
1823
+	{
1824
+		return $this->html_hashes[$matches[0]];
1825
+	}
1826 1826
 }
1827 1827
 
1828 1828
 #
@@ -1832,178 +1832,178 @@  discard block
 block discarded – undo
1832 1832
 class MarkdownExtra_Parser extends Markdown_Parser
1833 1833
 {
1834 1834
 
1835
-    ### Configuration Variables ###
1836
-
1837
-    # Prefix for footnote ids.
1838
-    var $fn_id_prefix = "";
1839
-
1840
-    # Optional title attribute for footnote links and backlinks.
1841
-    var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
1842
-
1843
-    var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
1844
-
1845
-    # Optional class attribute for footnote links and backlinks.
1846
-    var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
1847
-
1848
-    var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
1849
-
1850
-    # Optional class prefix for fenced code block.
1851
-    var $code_class_prefix = MARKDOWN_CODE_CLASS_PREFIX;
1835
+	### Configuration Variables ###
1836
+
1837
+	# Prefix for footnote ids.
1838
+	var $fn_id_prefix = "";
1839
+
1840
+	# Optional title attribute for footnote links and backlinks.
1841
+	var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
1842
+
1843
+	var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
1844
+
1845
+	# Optional class attribute for footnote links and backlinks.
1846
+	var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
1847
+
1848
+	var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
1849
+
1850
+	# Optional class prefix for fenced code block.
1851
+	var $code_class_prefix = MARKDOWN_CODE_CLASS_PREFIX;
1852 1852
 
1853
-    # Class attribute for code blocks goes on the `code` tag;
1854
-    # setting this to true will put attributes on the `pre` tag instead.
1855
-    var $code_attr_on_pre = MARKDOWN_CODE_ATTR_ON_PRE;
1853
+	# Class attribute for code blocks goes on the `code` tag;
1854
+	# setting this to true will put attributes on the `pre` tag instead.
1855
+	var $code_attr_on_pre = MARKDOWN_CODE_ATTR_ON_PRE;
1856 1856
 
1857
-    # Predefined abbreviations.
1858
-    var $predef_abbr = array();
1859
-
1860
-    ### Parser Implementation ###
1861
-
1862
-    function __construct()
1863
-    {
1864
-        #
1865
-        # Constructor function. Initialize the parser object.
1866
-        #
1867
-        # Add extra escapable characters before parent constructor
1868
-        # initialize the table.
1869
-        $this->escape_chars .= ':|';
1870
-
1871
-        # Insert extra document, block, and span transformations.
1872
-        # Parent constructor will do the sorting.
1873
-        $this->document_gamut += array(
1874
-            "doFencedCodeBlocks" => 5,
1875
-            "stripFootnotes"     => 15,
1876
-            "stripAbbreviations" => 25,
1877
-            "appendFootnotes"    => 50,
1878
-        );
1879
-        $this->block_gamut += array(
1880
-            "doFencedCodeBlocks" => 5,
1881
-            "doTables"           => 15,
1882
-            "doDefLists"         => 45,
1883
-        );
1884
-        $this->span_gamut += array(
1885
-            "doFootnotes"     => 5,
1886
-            "doAbbreviations" => 70,
1887
-        );
1888
-
1889
-        parent::__construct();
1890
-    }
1891
-
1892
-    # Extra variables used during extra transformations.
1893
-    var $footnotes = array();
1894
-
1895
-    var $footnotes_ordered = array();
1896
-
1897
-    var $footnotes_ref_count = array();
1898
-
1899
-    var $footnotes_numbers = array();
1900
-
1901
-    var $abbr_desciptions = array();
1902
-
1903
-    var $abbr_word_re = '';
1904
-
1905
-    # Give the current footnote number.
1906
-    var $footnote_counter = 1;
1907
-
1908
-    function setup()
1909
-    {
1910
-        #
1911
-        # Setting up Extra-specific variables.
1912
-        #
1913
-        parent::setup();
1914
-
1915
-        $this->footnotes           = array();
1916
-        $this->footnotes_ordered   = array();
1917
-        $this->footnotes_ref_count = array();
1918
-        $this->footnotes_numbers   = array();
1919
-        $this->abbr_desciptions    = array();
1920
-        $this->abbr_word_re        = '';
1921
-        $this->footnote_counter    = 1;
1922
-
1923
-        foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
1924
-            if ($this->abbr_word_re) {
1925
-                $this->abbr_word_re .= '|';
1926
-            }
1927
-            $this->abbr_word_re .= preg_quote($abbr_word);
1928
-            $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
1929
-        }
1930
-    }
1931
-
1932
-    function teardown()
1933
-    {
1934
-        #
1935
-        # Clearing Extra-specific variables.
1936
-        #
1937
-        $this->footnotes           = array();
1938
-        $this->footnotes_ordered   = array();
1939
-        $this->footnotes_ref_count = array();
1940
-        $this->footnotes_numbers   = array();
1941
-        $this->abbr_desciptions    = array();
1942
-        $this->abbr_word_re        = '';
1943
-
1944
-        parent::teardown();
1945
-    }
1946
-
1947
-
1948
-    ### Extra Attribute Parser ###
1949
-
1950
-    # Expression to use to catch attributes (includes the braces)
1951
-    var $id_class_attr_catch_re = '\{((?:[ ]*[#.][-_:a-zA-Z0-9]+){1,})[ ]*\}';
1952
-
1953
-    # Expression to use when parsing in a context when no capture is desired
1954
-    var $id_class_attr_nocatch_re = '\{(?:[ ]*[#.][-_:a-zA-Z0-9]+){1,}[ ]*\}';
1955
-
1956
-    function doExtraAttributes($tag_name, $attr)
1957
-    {
1958
-        #
1959
-        # Parse attributes caught by the $this->id_class_attr_catch_re expression
1960
-        # and return the HTML-formatted list of attributes.
1961
-        #
1962
-        # Currently supported attributes are .class and #id.
1963
-        #
1964
-        if (empty($attr)) {
1965
-            return "";
1966
-        }
1967
-
1968
-        # Split on components
1969
-        preg_match_all('/[#.][-_:a-zA-Z0-9]+/', $attr, $matches);
1970
-        $elements = $matches[0];
1971
-
1972
-        # handle classes and ids (only first id taken into account)
1973
-        $classes = array();
1974
-        $id      = false;
1975
-        foreach ($elements as $element) {
1976
-            if ($element{0} == '.') {
1977
-                $classes[] = substr($element, 1);
1978
-            } else if ($element{0} == '#') {
1979
-                if ($id === false) {
1980
-                    $id = substr($element, 1);
1981
-                }
1982
-            }
1983
-        }
1984
-
1985
-        # compose attributes as string
1986
-        $attr_str = "";
1987
-        if (!empty($id)) {
1988
-            $attr_str .= ' id="' . $id . '"';
1989
-        }
1990
-        if (!empty($classes)) {
1991
-            $attr_str .= ' class="' . implode(" ", $classes) . '"';
1992
-        }
1993
-        return $attr_str;
1994
-    }
1995
-
1996
-    function stripLinkDefinitions($text)
1997
-    {
1998
-        #
1999
-        # Strips link definitions from text, stores the URLs and titles in
2000
-        # hash references.
2001
-        #
2002
-        $less_than_tab = $this->tab_width - 1;
2003
-
2004
-        # Link defs are in the form: ^[id]: url "optional title"
2005
-        $text = preg_replace_callback(
2006
-            '{
1857
+	# Predefined abbreviations.
1858
+	var $predef_abbr = array();
1859
+
1860
+	### Parser Implementation ###
1861
+
1862
+	function __construct()
1863
+	{
1864
+		#
1865
+		# Constructor function. Initialize the parser object.
1866
+		#
1867
+		# Add extra escapable characters before parent constructor
1868
+		# initialize the table.
1869
+		$this->escape_chars .= ':|';
1870
+
1871
+		# Insert extra document, block, and span transformations.
1872
+		# Parent constructor will do the sorting.
1873
+		$this->document_gamut += array(
1874
+			"doFencedCodeBlocks" => 5,
1875
+			"stripFootnotes"     => 15,
1876
+			"stripAbbreviations" => 25,
1877
+			"appendFootnotes"    => 50,
1878
+		);
1879
+		$this->block_gamut += array(
1880
+			"doFencedCodeBlocks" => 5,
1881
+			"doTables"           => 15,
1882
+			"doDefLists"         => 45,
1883
+		);
1884
+		$this->span_gamut += array(
1885
+			"doFootnotes"     => 5,
1886
+			"doAbbreviations" => 70,
1887
+		);
1888
+
1889
+		parent::__construct();
1890
+	}
1891
+
1892
+	# Extra variables used during extra transformations.
1893
+	var $footnotes = array();
1894
+
1895
+	var $footnotes_ordered = array();
1896
+
1897
+	var $footnotes_ref_count = array();
1898
+
1899
+	var $footnotes_numbers = array();
1900
+
1901
+	var $abbr_desciptions = array();
1902
+
1903
+	var $abbr_word_re = '';
1904
+
1905
+	# Give the current footnote number.
1906
+	var $footnote_counter = 1;
1907
+
1908
+	function setup()
1909
+	{
1910
+		#
1911
+		# Setting up Extra-specific variables.
1912
+		#
1913
+		parent::setup();
1914
+
1915
+		$this->footnotes           = array();
1916
+		$this->footnotes_ordered   = array();
1917
+		$this->footnotes_ref_count = array();
1918
+		$this->footnotes_numbers   = array();
1919
+		$this->abbr_desciptions    = array();
1920
+		$this->abbr_word_re        = '';
1921
+		$this->footnote_counter    = 1;
1922
+
1923
+		foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
1924
+			if ($this->abbr_word_re) {
1925
+				$this->abbr_word_re .= '|';
1926
+			}
1927
+			$this->abbr_word_re .= preg_quote($abbr_word);
1928
+			$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
1929
+		}
1930
+	}
1931
+
1932
+	function teardown()
1933
+	{
1934
+		#
1935
+		# Clearing Extra-specific variables.
1936
+		#
1937
+		$this->footnotes           = array();
1938
+		$this->footnotes_ordered   = array();
1939
+		$this->footnotes_ref_count = array();
1940
+		$this->footnotes_numbers   = array();
1941
+		$this->abbr_desciptions    = array();
1942
+		$this->abbr_word_re        = '';
1943
+
1944
+		parent::teardown();
1945
+	}
1946
+
1947
+
1948
+	### Extra Attribute Parser ###
1949
+
1950
+	# Expression to use to catch attributes (includes the braces)
1951
+	var $id_class_attr_catch_re = '\{((?:[ ]*[#.][-_:a-zA-Z0-9]+){1,})[ ]*\}';
1952
+
1953
+	# Expression to use when parsing in a context when no capture is desired
1954
+	var $id_class_attr_nocatch_re = '\{(?:[ ]*[#.][-_:a-zA-Z0-9]+){1,}[ ]*\}';
1955
+
1956
+	function doExtraAttributes($tag_name, $attr)
1957
+	{
1958
+		#
1959
+		# Parse attributes caught by the $this->id_class_attr_catch_re expression
1960
+		# and return the HTML-formatted list of attributes.
1961
+		#
1962
+		# Currently supported attributes are .class and #id.
1963
+		#
1964
+		if (empty($attr)) {
1965
+			return "";
1966
+		}
1967
+
1968
+		# Split on components
1969
+		preg_match_all('/[#.][-_:a-zA-Z0-9]+/', $attr, $matches);
1970
+		$elements = $matches[0];
1971
+
1972
+		# handle classes and ids (only first id taken into account)
1973
+		$classes = array();
1974
+		$id      = false;
1975
+		foreach ($elements as $element) {
1976
+			if ($element{0} == '.') {
1977
+				$classes[] = substr($element, 1);
1978
+			} else if ($element{0} == '#') {
1979
+				if ($id === false) {
1980
+					$id = substr($element, 1);
1981
+				}
1982
+			}
1983
+		}
1984
+
1985
+		# compose attributes as string
1986
+		$attr_str = "";
1987
+		if (!empty($id)) {
1988
+			$attr_str .= ' id="' . $id . '"';
1989
+		}
1990
+		if (!empty($classes)) {
1991
+			$attr_str .= ' class="' . implode(" ", $classes) . '"';
1992
+		}
1993
+		return $attr_str;
1994
+	}
1995
+
1996
+	function stripLinkDefinitions($text)
1997
+	{
1998
+		#
1999
+		# Strips link definitions from text, stores the URLs and titles in
2000
+		# hash references.
2001
+		#
2002
+		$less_than_tab = $this->tab_width - 1;
2003
+
2004
+		# Link defs are in the form: ^[id]: url "optional title"
2005
+		$text = preg_replace_callback(
2006
+			'{
2007 2007
 							^[ ]{0,' . $less_than_tab . '}\[(.+)\][ ]?:	# id = $1
2008 2008
 							  [ ]*
2009 2009
 							  \n?				# maybe *one* newline
@@ -2026,117 +2026,117 @@  discard block
 block discarded – undo
2026 2026
 					(?:[ ]* ' . $this->id_class_attr_catch_re . ' )?  # $5 = extra id & class attr
2027 2027
 							(?:\n+|\Z)
2028 2028
 			}xm',
2029
-            array(&$this, '_stripLinkDefinitions_callback'),
2030
-            $text
2031
-        );
2032
-        return $text;
2033
-    }
2034
-
2035
-    function _stripLinkDefinitions_callback($matches)
2036
-    {
2037
-        $link_id                  = strtolower($matches[1]);
2038
-        $url                      = $matches[2] == '' ? $matches[3] : $matches[2];
2039
-        $this->urls[$link_id]     = $url;
2040
-        $this->titles[$link_id]   =& $matches[4];
2041
-        $this->ref_attr[$link_id] = $this->doExtraAttributes("", $dummy =& $matches[5]);
2042
-        return ''; # String that will replace the block
2043
-    }
2044
-
2045
-
2046
-    ### HTML Block Parser ###
2047
-
2048
-    # Tags that are always treated as block tags:
2049
-    var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend|article|section|nav|aside|hgroup|header|footer|figcaption';
2050
-
2051
-    # Tags treated as block tags only if the opening tag is alone on its line:
2052
-    var $context_block_tags_re = 'script|noscript|ins|del|iframe|object|source|track|param|math|svg|canvas|audio|video';
2053
-
2054
-    # Tags where markdown="1" default to span mode:
2055
-    var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
2056
-
2057
-    # Tags which must not have their contents modified, no matter where
2058
-    # they appear:
2059
-    var $clean_tags_re = 'script|math|svg';
2060
-
2061
-    # Tags that do not need to be closed.
2062
-    var $auto_close_tags_re = 'hr|img|param|source|track';
2063
-
2064
-    function hashHTMLBlocks($text)
2065
-    {
2066
-        #
2067
-        # Hashify HTML Blocks and "clean tags".
2068
-        #
2069
-        # We only want to do this for block-level HTML tags, such as headers,
2070
-        # lists, and tables. That's because we still want to wrap <p>s around
2071
-        # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
2072
-        # phrase emphasis, and spans. The list of tags we're looking for is
2073
-        # hard-coded.
2074
-        #
2075
-        # This works by calling _HashHTMLBlocks_InMarkdown, which then calls
2076
-        # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
2077
-        # attribute is found within a tag, _HashHTMLBlocks_InHTML calls back
2078
-        #  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
2079
-        # These two functions are calling each other. It's recursive!
2080
-        #
2081
-        if ($this->no_markup) {
2082
-            return $text;
2083
-        }
2084
-
2085
-        #
2086
-        # Call the HTML-in-Markdown hasher.
2087
-        #
2088
-        list($text,) = $this->_hashHTMLBlocks_inMarkdown($text);
2089
-
2090
-        return $text;
2091
-    }
2092
-
2093
-    function _hashHTMLBlocks_inMarkdown(
2094
-        $text,
2095
-        $indent = 0,
2096
-        $enclosing_tag_re = '',
2097
-        $span = false
2098
-    ) {
2099
-        #
2100
-        # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
2101
-        #
2102
-        # *   $indent is the number of space to be ignored when checking for code
2103
-        #     blocks. This is important because if we don't take the indent into
2104
-        #     account, something like this (which looks right) won't work as expected:
2105
-        #
2106
-        #     <div>
2107
-        #         <div markdown="1">
2108
-        #         Hello World.  <-- Is this a Markdown code block or text?
2109
-        #         </div>  <-- Is this a Markdown code block or a real tag?
2110
-        #     <div>
2111
-        #
2112
-        #     If you don't like this, just don't indent the tag on which
2113
-        #     you apply the markdown="1" attribute.
2114
-        #
2115
-        # *   If $enclosing_tag_re is not empty, stops at the first unmatched closing
2116
-        #     tag with that name. Nested tags supported.
2117
-        #
2118
-        # *   If $span is true, text inside must treated as span. So any double
2119
-        #     newline will be replaced by a single newline so that it does not create
2120
-        #     paragraphs.
2121
-        #
2122
-        # Returns an array of that form: ( processed text , remaining text )
2123
-        #
2124
-        if ($text === '') {
2125
-            return array('', '');
2126
-        }
2127
-
2128
-        # Regex to check for the presense of newlines around a block tag.
2129
-        $newline_before_re = '/(?:^\n?|\n\n)*$/';
2130
-        $newline_after_re  =
2131
-            '{
2029
+			array(&$this, '_stripLinkDefinitions_callback'),
2030
+			$text
2031
+		);
2032
+		return $text;
2033
+	}
2034
+
2035
+	function _stripLinkDefinitions_callback($matches)
2036
+	{
2037
+		$link_id                  = strtolower($matches[1]);
2038
+		$url                      = $matches[2] == '' ? $matches[3] : $matches[2];
2039
+		$this->urls[$link_id]     = $url;
2040
+		$this->titles[$link_id]   =& $matches[4];
2041
+		$this->ref_attr[$link_id] = $this->doExtraAttributes("", $dummy =& $matches[5]);
2042
+		return ''; # String that will replace the block
2043
+	}
2044
+
2045
+
2046
+	### HTML Block Parser ###
2047
+
2048
+	# Tags that are always treated as block tags:
2049
+	var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend|article|section|nav|aside|hgroup|header|footer|figcaption';
2050
+
2051
+	# Tags treated as block tags only if the opening tag is alone on its line:
2052
+	var $context_block_tags_re = 'script|noscript|ins|del|iframe|object|source|track|param|math|svg|canvas|audio|video';
2053
+
2054
+	# Tags where markdown="1" default to span mode:
2055
+	var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
2056
+
2057
+	# Tags which must not have their contents modified, no matter where
2058
+	# they appear:
2059
+	var $clean_tags_re = 'script|math|svg';
2060
+
2061
+	# Tags that do not need to be closed.
2062
+	var $auto_close_tags_re = 'hr|img|param|source|track';
2063
+
2064
+	function hashHTMLBlocks($text)
2065
+	{
2066
+		#
2067
+		# Hashify HTML Blocks and "clean tags".
2068
+		#
2069
+		# We only want to do this for block-level HTML tags, such as headers,
2070
+		# lists, and tables. That's because we still want to wrap <p>s around
2071
+		# "paragraphs" that are wrapped in non-block-level tags, such as anchors,
2072
+		# phrase emphasis, and spans. The list of tags we're looking for is
2073
+		# hard-coded.
2074
+		#
2075
+		# This works by calling _HashHTMLBlocks_InMarkdown, which then calls
2076
+		# _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
2077
+		# attribute is found within a tag, _HashHTMLBlocks_InHTML calls back
2078
+		#  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
2079
+		# These two functions are calling each other. It's recursive!
2080
+		#
2081
+		if ($this->no_markup) {
2082
+			return $text;
2083
+		}
2084
+
2085
+		#
2086
+		# Call the HTML-in-Markdown hasher.
2087
+		#
2088
+		list($text,) = $this->_hashHTMLBlocks_inMarkdown($text);
2089
+
2090
+		return $text;
2091
+	}
2092
+
2093
+	function _hashHTMLBlocks_inMarkdown(
2094
+		$text,
2095
+		$indent = 0,
2096
+		$enclosing_tag_re = '',
2097
+		$span = false
2098
+	) {
2099
+		#
2100
+		# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
2101
+		#
2102
+		# *   $indent is the number of space to be ignored when checking for code
2103
+		#     blocks. This is important because if we don't take the indent into
2104
+		#     account, something like this (which looks right) won't work as expected:
2105
+		#
2106
+		#     <div>
2107
+		#         <div markdown="1">
2108
+		#         Hello World.  <-- Is this a Markdown code block or text?
2109
+		#         </div>  <-- Is this a Markdown code block or a real tag?
2110
+		#     <div>
2111
+		#
2112
+		#     If you don't like this, just don't indent the tag on which
2113
+		#     you apply the markdown="1" attribute.
2114
+		#
2115
+		# *   If $enclosing_tag_re is not empty, stops at the first unmatched closing
2116
+		#     tag with that name. Nested tags supported.
2117
+		#
2118
+		# *   If $span is true, text inside must treated as span. So any double
2119
+		#     newline will be replaced by a single newline so that it does not create
2120
+		#     paragraphs.
2121
+		#
2122
+		# Returns an array of that form: ( processed text , remaining text )
2123
+		#
2124
+		if ($text === '') {
2125
+			return array('', '');
2126
+		}
2127
+
2128
+		# Regex to check for the presense of newlines around a block tag.
2129
+		$newline_before_re = '/(?:^\n?|\n\n)*$/';
2130
+		$newline_after_re  =
2131
+			'{
2132 2132
 				^						# Start of text following the tag.
2133 2133
 				(?>[ ]*<!--.*?-->)?		# Optional comment.
2134 2134
 				[ ]*\n					# Must be followed by newline.
2135 2135
 			}xs';
2136 2136
 
2137
-        # Regex to match any tag.
2138
-        $block_tag_re =
2139
-            '{
2137
+		# Regex to match any tag.
2138
+		$block_tag_re =
2139
+			'{
2140 2140
 				(					# $2: Capture whole tag.
2141 2141
 					</?					# Any opening or closing tag.
2142 2142
 						(?>				# Tag name.
@@ -2187,177 +2187,177 @@  discard block
 block discarded – undo
2187 2187
 				)
2188 2188
 			}xs';
2189 2189
 
2190
-        $depth  = 0; # Current depth inside the tag tree.
2191
-        $parsed = ""; # Parsed text that will be returned.
2192
-
2193
-        #
2194
-        # Loop through every tag until we find the closing tag of the parent
2195
-        # or loop until reaching the end of text if no parent tag specified.
2196
-        #
2197
-        do {
2198
-            #
2199
-            # Split the text using the first $tag_match pattern found.
2200
-            # Text before  pattern will be first in the array, text after
2201
-            # pattern will be at the end, and between will be any catches made
2202
-            # by the pattern.
2203
-            #
2204
-            $parts = preg_split(
2205
-                $block_tag_re,
2206
-                $text,
2207
-                2,
2208
-                PREG_SPLIT_DELIM_CAPTURE
2209
-            );
2210
-
2211
-            # If in Markdown span mode, add a empty-string span-level hash
2212
-            # after each newline to prevent triggering any block element.
2213
-            if ($span) {
2214
-                $void     = $this->hashPart("", ':');
2215
-                $newline  = "$void\n";
2216
-                $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
2217
-            }
2218
-
2219
-            $parsed .= $parts[0]; # Text before current tag.
2220
-
2221
-            # If end of $text has been reached. Stop loop.
2222
-            if (count($parts) < 3) {
2223
-                $text = "";
2224
-                break;
2225
-            }
2226
-
2227
-            $tag    = $parts[1]; # Tag to handle.
2228
-            $text   = $parts[2]; # Remaining text after current tag.
2229
-            $tag_re = preg_quote($tag); # For use in a regular expression.
2230
-
2231
-            #
2232
-            # Check for: Code span marker
2233
-            #
2234
-            if ($tag{0} == "`") {
2235
-                # Find corresponding end marker.
2236
-                $tag_re = preg_quote($tag);
2237
-                if (preg_match(
2238
-                    '{^(?>.+?|\n(?!\n))*?(?<!`)' . $tag_re . '(?!`)}',
2239
-                    $text,
2240
-                    $matches
2241
-                )) {
2242
-                    # End marker found: pass text unchanged until marker.
2243
-                    $parsed .= $tag . $matches[0];
2244
-                    $text = substr($text, strlen($matches[0]));
2245
-                } else {
2246
-                    # Unmatched marker: just skip it.
2247
-                    $parsed .= $tag;
2248
-                }
2249
-            }
2250
-            #
2251
-            # Check for: Fenced code block marker.
2252
-            #
2253
-            else if (preg_match('{^\n?([ ]{0,' . ($indent + 3) . '})(~+)}', $tag, $capture)) {
2254
-                # Fenced code block marker: find matching end marker.
2255
-                $fence_indent = strlen($capture[1]); # use captured indent in re
2256
-                $fence_re     = $capture[2]; # use captured fence in re
2257
-                if (preg_match(
2258
-                    '{^(?>.*\n)*?[ ]{' . ($fence_indent) . '}' . $fence_re . '[ ]*(?:\n|$)}',
2259
-                    $text,
2260
-                    $matches
2261
-                )) {
2262
-                    # End marker found: pass text unchanged until marker.
2263
-                    $parsed .= $tag . $matches[0];
2264
-                    $text = substr($text, strlen($matches[0]));
2265
-                } else {
2266
-                    # No end marker: just skip it.
2267
-                    $parsed .= $tag;
2268
-                }
2269
-            }
2270
-            #
2271
-            # Check for: Indented code block.
2272
-            #
2273
-            else if ($tag{0} == "\n" || $tag{0} == " ") {
2274
-                # Indented code block: pass it unchanged, will be handled
2275
-                # later.
2276
-                $parsed .= $tag;
2277
-            }
2278
-            #
2279
-            # Check for: Opening Block level tag or
2280
-            #            Opening Context Block tag (like ins and del)
2281
-            #               used as a block tag (tag is alone on it's line).
2282
-            #
2283
-            else if (preg_match('{^<(?:' . $this->block_tags_re . ')\b}', $tag) ||
2284
-                     (preg_match('{^<(?:' . $this->context_block_tags_re . ')\b}', $tag) &&
2285
-                      preg_match($newline_before_re, $parsed) &&
2286
-                      preg_match($newline_after_re, $text))
2287
-            ) {
2288
-                # Need to parse tag and following text using the HTML parser.
2289
-                list($block_text, $text) =
2290
-                    $this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
2291
-
2292
-                # Make sure it stays outside of any paragraph by adding newlines.
2293
-                $parsed .= "\n\n$block_text\n\n";
2294
-            }
2295
-            #
2296
-            # Check for: Clean tag (like script, math)
2297
-            #            HTML Comments, processing instructions.
2298
-            #
2299
-            else if (preg_match('{^<(?:' . $this->clean_tags_re . ')\b}', $tag) ||
2300
-                     $tag{1} == '!' || $tag{1} == '?'
2301
-            ) {
2302
-                # Need to parse tag and following text using the HTML parser.
2303
-                # (don't check for markdown attribute)
2304
-                list($block_text, $text) =
2305
-                    $this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
2306
-
2307
-                $parsed .= $block_text;
2308
-            }
2309
-            #
2310
-            # Check for: Tag with same name as enclosing tag.
2311
-            #
2312
-            else if ($enclosing_tag_re !== '' &&
2313
-                     # Same name as enclosing tag.
2314
-                     preg_match('{^</?(?:' . $enclosing_tag_re . ')\b}', $tag)
2315
-            ) {
2316
-                #
2317
-                # Increase/decrease nested tag count.
2318
-                #
2319
-                if ($tag{1} == '/') {
2320
-                    $depth --;
2321
-                } else if ($tag{strlen($tag) - 2} != '/') {
2322
-                    $depth ++;
2323
-                }
2324
-
2325
-                if ($depth < 0) {
2326
-                    #
2327
-                    # Going out of parent element. Clean up and break so we
2328
-                    # return to the calling function.
2329
-                    #
2330
-                    $text = $tag . $text;
2331
-                    break;
2332
-                }
2333
-
2334
-                $parsed .= $tag;
2335
-            } else {
2336
-                $parsed .= $tag;
2337
-            }
2338
-        } while ($depth >= 0);
2339
-
2340
-        return array($parsed, $text);
2341
-    }
2342
-
2343
-    function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr)
2344
-    {
2345
-        #
2346
-        # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
2347
-        #
2348
-        # *   Calls $hash_method to convert any blocks.
2349
-        # *   Stops when the first opening tag closes.
2350
-        # *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
2351
-        #     (it is not inside clean tags)
2352
-        #
2353
-        # Returns an array of that form: ( processed text , remaining text )
2354
-        #
2355
-        if ($text === '') {
2356
-            return array('', '');
2357
-        }
2358
-
2359
-        # Regex to match `markdown` attribute inside of a tag.
2360
-        $markdown_attr_re = '
2190
+		$depth  = 0; # Current depth inside the tag tree.
2191
+		$parsed = ""; # Parsed text that will be returned.
2192
+
2193
+		#
2194
+		# Loop through every tag until we find the closing tag of the parent
2195
+		# or loop until reaching the end of text if no parent tag specified.
2196
+		#
2197
+		do {
2198
+			#
2199
+			# Split the text using the first $tag_match pattern found.
2200
+			# Text before  pattern will be first in the array, text after
2201
+			# pattern will be at the end, and between will be any catches made
2202
+			# by the pattern.
2203
+			#
2204
+			$parts = preg_split(
2205
+				$block_tag_re,
2206
+				$text,
2207
+				2,
2208
+				PREG_SPLIT_DELIM_CAPTURE
2209
+			);
2210
+
2211
+			# If in Markdown span mode, add a empty-string span-level hash
2212
+			# after each newline to prevent triggering any block element.
2213
+			if ($span) {
2214
+				$void     = $this->hashPart("", ':');
2215
+				$newline  = "$void\n";
2216
+				$parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
2217
+			}
2218
+
2219
+			$parsed .= $parts[0]; # Text before current tag.
2220
+
2221
+			# If end of $text has been reached. Stop loop.
2222
+			if (count($parts) < 3) {
2223
+				$text = "";
2224
+				break;
2225
+			}
2226
+
2227
+			$tag    = $parts[1]; # Tag to handle.
2228
+			$text   = $parts[2]; # Remaining text after current tag.
2229
+			$tag_re = preg_quote($tag); # For use in a regular expression.
2230
+
2231
+			#
2232
+			# Check for: Code span marker
2233
+			#
2234
+			if ($tag{0} == "`") {
2235
+				# Find corresponding end marker.
2236
+				$tag_re = preg_quote($tag);
2237
+				if (preg_match(
2238
+					'{^(?>.+?|\n(?!\n))*?(?<!`)' . $tag_re . '(?!`)}',
2239
+					$text,
2240
+					$matches
2241
+				)) {
2242
+					# End marker found: pass text unchanged until marker.
2243
+					$parsed .= $tag . $matches[0];
2244
+					$text = substr($text, strlen($matches[0]));
2245
+				} else {
2246
+					# Unmatched marker: just skip it.
2247
+					$parsed .= $tag;
2248
+				}
2249
+			}
2250
+			#
2251
+			# Check for: Fenced code block marker.
2252
+			#
2253
+			else if (preg_match('{^\n?([ ]{0,' . ($indent + 3) . '})(~+)}', $tag, $capture)) {
2254
+				# Fenced code block marker: find matching end marker.
2255
+				$fence_indent = strlen($capture[1]); # use captured indent in re
2256
+				$fence_re     = $capture[2]; # use captured fence in re
2257
+				if (preg_match(
2258
+					'{^(?>.*\n)*?[ ]{' . ($fence_indent) . '}' . $fence_re . '[ ]*(?:\n|$)}',
2259
+					$text,
2260
+					$matches
2261
+				)) {
2262
+					# End marker found: pass text unchanged until marker.
2263
+					$parsed .= $tag . $matches[0];
2264
+					$text = substr($text, strlen($matches[0]));
2265
+				} else {
2266
+					# No end marker: just skip it.
2267
+					$parsed .= $tag;
2268
+				}
2269
+			}
2270
+			#
2271
+			# Check for: Indented code block.
2272
+			#
2273
+			else if ($tag{0} == "\n" || $tag{0} == " ") {
2274
+				# Indented code block: pass it unchanged, will be handled
2275
+				# later.
2276
+				$parsed .= $tag;
2277
+			}
2278
+			#
2279
+			# Check for: Opening Block level tag or
2280
+			#            Opening Context Block tag (like ins and del)
2281
+			#               used as a block tag (tag is alone on it's line).
2282
+			#
2283
+			else if (preg_match('{^<(?:' . $this->block_tags_re . ')\b}', $tag) ||
2284
+					 (preg_match('{^<(?:' . $this->context_block_tags_re . ')\b}', $tag) &&
2285
+					  preg_match($newline_before_re, $parsed) &&
2286
+					  preg_match($newline_after_re, $text))
2287
+			) {
2288
+				# Need to parse tag and following text using the HTML parser.
2289
+				list($block_text, $text) =
2290
+					$this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
2291
+
2292
+				# Make sure it stays outside of any paragraph by adding newlines.
2293
+				$parsed .= "\n\n$block_text\n\n";
2294
+			}
2295
+			#
2296
+			# Check for: Clean tag (like script, math)
2297
+			#            HTML Comments, processing instructions.
2298
+			#
2299
+			else if (preg_match('{^<(?:' . $this->clean_tags_re . ')\b}', $tag) ||
2300
+					 $tag{1} == '!' || $tag{1} == '?'
2301
+			) {
2302
+				# Need to parse tag and following text using the HTML parser.
2303
+				# (don't check for markdown attribute)
2304
+				list($block_text, $text) =
2305
+					$this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
2306
+
2307
+				$parsed .= $block_text;
2308
+			}
2309
+			#
2310
+			# Check for: Tag with same name as enclosing tag.
2311
+			#
2312
+			else if ($enclosing_tag_re !== '' &&
2313
+					 # Same name as enclosing tag.
2314
+					 preg_match('{^</?(?:' . $enclosing_tag_re . ')\b}', $tag)
2315
+			) {
2316
+				#
2317
+				# Increase/decrease nested tag count.
2318
+				#
2319
+				if ($tag{1} == '/') {
2320
+					$depth --;
2321
+				} else if ($tag{strlen($tag) - 2} != '/') {
2322
+					$depth ++;
2323
+				}
2324
+
2325
+				if ($depth < 0) {
2326
+					#
2327
+					# Going out of parent element. Clean up and break so we
2328
+					# return to the calling function.
2329
+					#
2330
+					$text = $tag . $text;
2331
+					break;
2332
+				}
2333
+
2334
+				$parsed .= $tag;
2335
+			} else {
2336
+				$parsed .= $tag;
2337
+			}
2338
+		} while ($depth >= 0);
2339
+
2340
+		return array($parsed, $text);
2341
+	}
2342
+
2343
+	function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr)
2344
+	{
2345
+		#
2346
+		# Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
2347
+		#
2348
+		# *   Calls $hash_method to convert any blocks.
2349
+		# *   Stops when the first opening tag closes.
2350
+		# *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
2351
+		#     (it is not inside clean tags)
2352
+		#
2353
+		# Returns an array of that form: ( processed text , remaining text )
2354
+		#
2355
+		if ($text === '') {
2356
+			return array('', '');
2357
+		}
2358
+
2359
+		# Regex to match `markdown` attribute inside of a tag.
2360
+		$markdown_attr_re = '
2361 2361
 			{
2362 2362
 				\s*			# Eat whitespace before the `markdown` attribute
2363 2363
 				markdown
@@ -2372,8 +2372,8 @@  discard block
 block discarded – undo
2372 2372
 				()				# $4: make $3 always defined (avoid warnings)
2373 2373
 			}xs';
2374 2374
 
2375
-        # Regex to match any tag.
2376
-        $tag_re = '{
2375
+		# Regex to match any tag.
2376
+		$tag_re = '{
2377 2377
 				(					# $2: Capture whole tag.
2378 2378
 					</?					# Any opening or closing tag.
2379 2379
 						[\w:$]+			# Tag name.
@@ -2395,169 +2395,169 @@  discard block
 block discarded – undo
2395 2395
 				)
2396 2396
 			}xs';
2397 2397
 
2398
-        $original_text = $text; # Save original text in case of faliure.
2399
-
2400
-        $depth      = 0; # Current depth inside the tag tree.
2401
-        $block_text = ""; # Temporary text holder for current text.
2402
-        $parsed     = ""; # Parsed text that will be returned.
2403
-
2404
-        #
2405
-        # Get the name of the starting tag.
2406
-        # (This pattern makes $base_tag_name_re safe without quoting.)
2407
-        #
2408
-        if (preg_match('/^<([\w:$]*)\b/', $text, $matches)) {
2409
-            $base_tag_name_re = $matches[1];
2410
-        }
2411
-
2412
-        #
2413
-        # Loop through every tag until we find the corresponding closing tag.
2414
-        #
2415
-        do {
2416
-            #
2417
-            # Split the text using the first $tag_match pattern found.
2418
-            # Text before  pattern will be first in the array, text after
2419
-            # pattern will be at the end, and between will be any catches made
2420
-            # by the pattern.
2421
-            #
2422
-            $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
2423
-
2424
-            if (count($parts) < 3) {
2425
-                #
2426
-                # End of $text reached with unbalenced tag(s).
2427
-                # In that case, we return original text unchanged and pass the
2428
-                # first character as filtered to prevent an infinite loop in the
2429
-                # parent function.
2430
-                #
2431
-                return array($original_text{0}, substr($original_text, 1));
2432
-            }
2433
-
2434
-            $block_text .= $parts[0]; # Text before current tag.
2435
-            $tag  = $parts[1]; # Tag to handle.
2436
-            $text = $parts[2]; # Remaining text after current tag.
2437
-
2438
-            #
2439
-            # Check for: Auto-close tag (like <hr/>)
2440
-            #			 Comments and Processing Instructions.
2441
-            #
2442
-            if (preg_match('{^</?(?:' . $this->auto_close_tags_re . ')\b}', $tag) ||
2443
-                $tag{1} == '!' || $tag{1} == '?'
2444
-            ) {
2445
-                # Just add the tag to the block as if it was text.
2446
-                $block_text .= $tag;
2447
-            } else {
2448
-                #
2449
-                # Increase/decrease nested tag count. Only do so if
2450
-                # the tag's name match base tag's.
2451
-                #
2452
-                if (preg_match('{^</?' . $base_tag_name_re . '\b}', $tag)) {
2453
-                    if ($tag{1} == '/') {
2454
-                        $depth --;
2455
-                    } else if ($tag{strlen($tag) - 2} != '/') {
2456
-                        $depth ++;
2457
-                    }
2458
-                }
2459
-
2460
-                #
2461
-                # Check for `markdown="1"` attribute and handle it.
2462
-                #
2463
-                if ($md_attr &&
2464
-                    preg_match($markdown_attr_re, $tag, $attr_m) &&
2465
-                    preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3])
2466
-                ) {
2467
-                    # Remove `markdown` attribute from opening tag.
2468
-                    $tag = preg_replace($markdown_attr_re, '', $tag);
2469
-
2470
-                    # Check if text inside this tag must be parsed in span mode.
2471
-                    $this->mode = $attr_m[2] . $attr_m[3];
2472
-                    $span_mode  = $this->mode == 'span' || $this->mode != 'block' &&
2473
-                                                           preg_match(
2474
-                                                               '{^<(?:' . $this->contain_span_tags_re . ')\b}',
2475
-                                                               $tag
2476
-                                                           );
2477
-
2478
-                    # Calculate indent before tag.
2479
-                    if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
2480
-                        $strlen = $this->utf8_strlen;
2481
-                        $indent = $strlen($matches[1], 'UTF-8');
2482
-                    } else {
2483
-                        $indent = 0;
2484
-                    }
2485
-
2486
-                    # End preceding block with this tag.
2487
-                    $block_text .= $tag;
2488
-                    $parsed .= $this->$hash_method($block_text);
2489
-
2490
-                    # Get enclosing tag name for the ParseMarkdown function.
2491
-                    # (This pattern makes $tag_name_re safe without quoting.)
2492
-                    preg_match('/^<([\w:$]*)\b/', $tag, $matches);
2493
-                    $tag_name_re = $matches[1];
2494
-
2495
-                    # Parse the content using the HTML-in-Markdown parser.
2496
-                    list ($block_text, $text)
2497
-                        = $this->_hashHTMLBlocks_inMarkdown(
2498
-                        $text,
2499
-                        $indent,
2500
-                        $tag_name_re,
2501
-                        $span_mode
2502
-                    );
2503
-
2504
-                    # Outdent markdown text.
2505
-                    if ($indent > 0) {
2506
-                        $block_text = preg_replace(
2507
-                            "/^[ ]{1,$indent}/m",
2508
-                            "",
2509
-                            $block_text
2510
-                        );
2511
-                    }
2512
-
2513
-                    # Append tag content to parsed text.
2514
-                    if (!$span_mode) {
2515
-                        $parsed .= "\n\n$block_text\n\n";
2516
-                    } else {
2517
-                        $parsed .= "$block_text";
2518
-                    }
2519
-
2520
-                    # Start over with a new block.
2521
-                    $block_text = "";
2522
-                } else {
2523
-                    $block_text .= $tag;
2524
-                }
2525
-            }
2526
-        } while ($depth > 0);
2527
-
2528
-        #
2529
-        # Hash last block text that wasn't processed inside the loop.
2530
-        #
2531
-        $parsed .= $this->$hash_method($block_text);
2532
-
2533
-        return array($parsed, $text);
2534
-    }
2535
-
2536
-    function hashClean($text)
2537
-    {
2538
-        #
2539
-        # Called whenever a tag must be hashed when a function inserts a "clean" tag
2540
-        # in $text, it passes through this function and is automaticaly escaped,
2541
-        # blocking invalid nested overlap.
2542
-        #
2543
-        return $this->hashPart($text, 'C');
2544
-    }
2545
-
2546
-    function doAnchors($text)
2547
-    {
2548
-        #
2549
-        # Turn Markdown link shortcuts into XHTML <a> tags.
2550
-        #
2551
-        if ($this->in_anchor) {
2552
-            return $text;
2553
-        }
2554
-        $this->in_anchor = true;
2555
-
2556
-        #
2557
-        # First, handle reference-style links: [link text] [id]
2558
-        #
2559
-        $text = preg_replace_callback(
2560
-            '{
2398
+		$original_text = $text; # Save original text in case of faliure.
2399
+
2400
+		$depth      = 0; # Current depth inside the tag tree.
2401
+		$block_text = ""; # Temporary text holder for current text.
2402
+		$parsed     = ""; # Parsed text that will be returned.
2403
+
2404
+		#
2405
+		# Get the name of the starting tag.
2406
+		# (This pattern makes $base_tag_name_re safe without quoting.)
2407
+		#
2408
+		if (preg_match('/^<([\w:$]*)\b/', $text, $matches)) {
2409
+			$base_tag_name_re = $matches[1];
2410
+		}
2411
+
2412
+		#
2413
+		# Loop through every tag until we find the corresponding closing tag.
2414
+		#
2415
+		do {
2416
+			#
2417
+			# Split the text using the first $tag_match pattern found.
2418
+			# Text before  pattern will be first in the array, text after
2419
+			# pattern will be at the end, and between will be any catches made
2420
+			# by the pattern.
2421
+			#
2422
+			$parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
2423
+
2424
+			if (count($parts) < 3) {
2425
+				#
2426
+				# End of $text reached with unbalenced tag(s).
2427
+				# In that case, we return original text unchanged and pass the
2428
+				# first character as filtered to prevent an infinite loop in the
2429
+				# parent function.
2430
+				#
2431
+				return array($original_text{0}, substr($original_text, 1));
2432
+			}
2433
+
2434
+			$block_text .= $parts[0]; # Text before current tag.
2435
+			$tag  = $parts[1]; # Tag to handle.
2436
+			$text = $parts[2]; # Remaining text after current tag.
2437
+
2438
+			#
2439
+			# Check for: Auto-close tag (like <hr/>)
2440
+			#			 Comments and Processing Instructions.
2441
+			#
2442
+			if (preg_match('{^</?(?:' . $this->auto_close_tags_re . ')\b}', $tag) ||
2443
+				$tag{1} == '!' || $tag{1} == '?'
2444
+			) {
2445
+				# Just add the tag to the block as if it was text.
2446
+				$block_text .= $tag;
2447
+			} else {
2448
+				#
2449
+				# Increase/decrease nested tag count. Only do so if
2450
+				# the tag's name match base tag's.
2451
+				#
2452
+				if (preg_match('{^</?' . $base_tag_name_re . '\b}', $tag)) {
2453
+					if ($tag{1} == '/') {
2454
+						$depth --;
2455
+					} else if ($tag{strlen($tag) - 2} != '/') {
2456
+						$depth ++;
2457
+					}
2458
+				}
2459
+
2460
+				#
2461
+				# Check for `markdown="1"` attribute and handle it.
2462
+				#
2463
+				if ($md_attr &&
2464
+					preg_match($markdown_attr_re, $tag, $attr_m) &&
2465
+					preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3])
2466
+				) {
2467
+					# Remove `markdown` attribute from opening tag.
2468
+					$tag = preg_replace($markdown_attr_re, '', $tag);
2469
+
2470
+					# Check if text inside this tag must be parsed in span mode.
2471
+					$this->mode = $attr_m[2] . $attr_m[3];
2472
+					$span_mode  = $this->mode == 'span' || $this->mode != 'block' &&
2473
+														   preg_match(
2474
+															   '{^<(?:' . $this->contain_span_tags_re . ')\b}',
2475
+															   $tag
2476
+														   );
2477
+
2478
+					# Calculate indent before tag.
2479
+					if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
2480
+						$strlen = $this->utf8_strlen;
2481
+						$indent = $strlen($matches[1], 'UTF-8');
2482
+					} else {
2483
+						$indent = 0;
2484
+					}
2485
+
2486
+					# End preceding block with this tag.
2487
+					$block_text .= $tag;
2488
+					$parsed .= $this->$hash_method($block_text);
2489
+
2490
+					# Get enclosing tag name for the ParseMarkdown function.
2491
+					# (This pattern makes $tag_name_re safe without quoting.)
2492
+					preg_match('/^<([\w:$]*)\b/', $tag, $matches);
2493
+					$tag_name_re = $matches[1];
2494
+
2495
+					# Parse the content using the HTML-in-Markdown parser.
2496
+					list ($block_text, $text)
2497
+						= $this->_hashHTMLBlocks_inMarkdown(
2498
+						$text,
2499
+						$indent,
2500
+						$tag_name_re,
2501
+						$span_mode
2502
+					);
2503
+
2504
+					# Outdent markdown text.
2505
+					if ($indent > 0) {
2506
+						$block_text = preg_replace(
2507
+							"/^[ ]{1,$indent}/m",
2508
+							"",
2509
+							$block_text
2510
+						);
2511
+					}
2512
+
2513
+					# Append tag content to parsed text.
2514
+					if (!$span_mode) {
2515
+						$parsed .= "\n\n$block_text\n\n";
2516
+					} else {
2517
+						$parsed .= "$block_text";
2518
+					}
2519
+
2520
+					# Start over with a new block.
2521
+					$block_text = "";
2522
+				} else {
2523
+					$block_text .= $tag;
2524
+				}
2525
+			}
2526
+		} while ($depth > 0);
2527
+
2528
+		#
2529
+		# Hash last block text that wasn't processed inside the loop.
2530
+		#
2531
+		$parsed .= $this->$hash_method($block_text);
2532
+
2533
+		return array($parsed, $text);
2534
+	}
2535
+
2536
+	function hashClean($text)
2537
+	{
2538
+		#
2539
+		# Called whenever a tag must be hashed when a function inserts a "clean" tag
2540
+		# in $text, it passes through this function and is automaticaly escaped,
2541
+		# blocking invalid nested overlap.
2542
+		#
2543
+		return $this->hashPart($text, 'C');
2544
+	}
2545
+
2546
+	function doAnchors($text)
2547
+	{
2548
+		#
2549
+		# Turn Markdown link shortcuts into XHTML <a> tags.
2550
+		#
2551
+		if ($this->in_anchor) {
2552
+			return $text;
2553
+		}
2554
+		$this->in_anchor = true;
2555
+
2556
+		#
2557
+		# First, handle reference-style links: [link text] [id]
2558
+		#
2559
+		$text = preg_replace_callback(
2560
+			'{
2561 2561
 			(					# wrap whole match in $1
2562 2562
 			  \[
2563 2563
 				(' . $this->nested_brackets_re . ')	# link text = $2
@@ -2571,15 +2571,15 @@  discard block
 block discarded – undo
2571 2571
 			  \]
2572 2572
 			)
2573 2573
 			}xs',
2574
-            array(&$this, '_doAnchors_reference_callback'),
2575
-            $text
2576
-        );
2577
-
2578
-        #
2579
-        # Next, inline-style links: [link text](url "optional title")
2580
-        #
2581
-        $text = preg_replace_callback(
2582
-            '{
2574
+			array(&$this, '_doAnchors_reference_callback'),
2575
+			$text
2576
+		);
2577
+
2578
+		#
2579
+		# Next, inline-style links: [link text](url "optional title")
2580
+		#
2581
+		$text = preg_replace_callback(
2582
+			'{
2583 2583
 			(				# wrap whole match in $1
2584 2584
 			  \[
2585 2585
 				(' . $this->nested_brackets_re . ')	# link text = $2
@@ -2602,102 +2602,102 @@  discard block
 block discarded – undo
2602 2602
 			  (?:[ ]? ' . $this->id_class_attr_catch_re . ' )?	 # $8 = id/class attributes
2603 2603
 			)
2604 2604
 			}xs',
2605
-            array(&$this, '_doAnchors_inline_callback'),
2606
-            $text
2607
-        );
2608
-
2609
-        #
2610
-        # Last, handle reference-style shortcuts: [link text]
2611
-        # These must come last in case you've also got [link text][1]
2612
-        # or [link text](/foo)
2613
-        #
2614
-        $text = preg_replace_callback(
2615
-            '{
2605
+			array(&$this, '_doAnchors_inline_callback'),
2606
+			$text
2607
+		);
2608
+
2609
+		#
2610
+		# Last, handle reference-style shortcuts: [link text]
2611
+		# These must come last in case you've also got [link text][1]
2612
+		# or [link text](/foo)
2613
+		#
2614
+		$text = preg_replace_callback(
2615
+			'{
2616 2616
 			(					# wrap whole match in $1
2617 2617
 			  \[
2618 2618
 				([^\[\]]+)		# link text = $2; can\'t contain [ or ]
2619 2619
 			  \]
2620 2620
 			)
2621 2621
 			}xs',
2622
-            array(&$this, '_doAnchors_reference_callback'),
2623
-            $text
2624
-        );
2625
-
2626
-        $this->in_anchor = false;
2627
-        return $text;
2628
-    }
2629
-
2630
-    function _doAnchors_reference_callback($matches)
2631
-    {
2632
-        $whole_match = $matches[1];
2633
-        $link_text   = $matches[2];
2634
-        $link_id     =& $matches[3];
2635
-
2636
-        if ($link_id == "") {
2637
-            # for shortcut links like [this][] or [this].
2638
-            $link_id = $link_text;
2639
-        }
2640
-
2641
-        # lower-case and turn embedded newlines into spaces
2642
-        $link_id = strtolower($link_id);
2643
-        $link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
2644
-
2645
-        if (isset($this->urls[$link_id])) {
2646
-            $url = $this->urls[$link_id];
2647
-            $url = $this->encodeAttribute($url);
2648
-
2649
-            $result = "<a href=\"$url\"";
2650
-            if (isset($this->titles[$link_id])) {
2651
-                $title = $this->titles[$link_id];
2652
-                $title = $this->encodeAttribute($title);
2653
-                $result .= " title=\"$title\"";
2654
-            }
2655
-            if (isset($this->ref_attr[$link_id])) {
2656
-                $result .= $this->ref_attr[$link_id];
2657
-            }
2658
-
2659
-            $link_text = $this->runSpanGamut($link_text);
2660
-            $result .= ">$link_text</a>";
2661
-            $result = $this->hashPart($result);
2662
-        } else {
2663
-            $result = $whole_match;
2664
-        }
2665
-        return $result;
2666
-    }
2667
-
2668
-    function _doAnchors_inline_callback($matches)
2669
-    {
2670
-        $whole_match = $matches[1];
2671
-        $link_text   = $this->runSpanGamut($matches[2]);
2672
-        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
2673
-        $title       =& $matches[7];
2674
-        $attr        = $this->doExtraAttributes("a", $dummy =& $matches[8]);
2675
-
2676
-        $url = $this->encodeAttribute($url);
2677
-
2678
-        $result = "<a href=\"$url\"";
2679
-        if (isset($title)) {
2680
-            $title = $this->encodeAttribute($title);
2681
-            $result .= " title=\"$title\"";
2682
-        }
2683
-        $result .= $attr;
2684
-
2685
-        $link_text = $this->runSpanGamut($link_text);
2686
-        $result .= ">$link_text</a>";
2687
-
2688
-        return $this->hashPart($result);
2689
-    }
2690
-
2691
-    function doImages($text)
2692
-    {
2693
-        #
2694
-        # Turn Markdown image shortcuts into <img> tags.
2695
-        #
2696
-        #
2697
-        # First, handle reference-style labeled images: ![alt text][id]
2698
-        #
2699
-        $text = preg_replace_callback(
2700
-            '{
2622
+			array(&$this, '_doAnchors_reference_callback'),
2623
+			$text
2624
+		);
2625
+
2626
+		$this->in_anchor = false;
2627
+		return $text;
2628
+	}
2629
+
2630
+	function _doAnchors_reference_callback($matches)
2631
+	{
2632
+		$whole_match = $matches[1];
2633
+		$link_text   = $matches[2];
2634
+		$link_id     =& $matches[3];
2635
+
2636
+		if ($link_id == "") {
2637
+			# for shortcut links like [this][] or [this].
2638
+			$link_id = $link_text;
2639
+		}
2640
+
2641
+		# lower-case and turn embedded newlines into spaces
2642
+		$link_id = strtolower($link_id);
2643
+		$link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
2644
+
2645
+		if (isset($this->urls[$link_id])) {
2646
+			$url = $this->urls[$link_id];
2647
+			$url = $this->encodeAttribute($url);
2648
+
2649
+			$result = "<a href=\"$url\"";
2650
+			if (isset($this->titles[$link_id])) {
2651
+				$title = $this->titles[$link_id];
2652
+				$title = $this->encodeAttribute($title);
2653
+				$result .= " title=\"$title\"";
2654
+			}
2655
+			if (isset($this->ref_attr[$link_id])) {
2656
+				$result .= $this->ref_attr[$link_id];
2657
+			}
2658
+
2659
+			$link_text = $this->runSpanGamut($link_text);
2660
+			$result .= ">$link_text</a>";
2661
+			$result = $this->hashPart($result);
2662
+		} else {
2663
+			$result = $whole_match;
2664
+		}
2665
+		return $result;
2666
+	}
2667
+
2668
+	function _doAnchors_inline_callback($matches)
2669
+	{
2670
+		$whole_match = $matches[1];
2671
+		$link_text   = $this->runSpanGamut($matches[2]);
2672
+		$url         = $matches[3] == '' ? $matches[4] : $matches[3];
2673
+		$title       =& $matches[7];
2674
+		$attr        = $this->doExtraAttributes("a", $dummy =& $matches[8]);
2675
+
2676
+		$url = $this->encodeAttribute($url);
2677
+
2678
+		$result = "<a href=\"$url\"";
2679
+		if (isset($title)) {
2680
+			$title = $this->encodeAttribute($title);
2681
+			$result .= " title=\"$title\"";
2682
+		}
2683
+		$result .= $attr;
2684
+
2685
+		$link_text = $this->runSpanGamut($link_text);
2686
+		$result .= ">$link_text</a>";
2687
+
2688
+		return $this->hashPart($result);
2689
+	}
2690
+
2691
+	function doImages($text)
2692
+	{
2693
+		#
2694
+		# Turn Markdown image shortcuts into <img> tags.
2695
+		#
2696
+		#
2697
+		# First, handle reference-style labeled images: ![alt text][id]
2698
+		#
2699
+		$text = preg_replace_callback(
2700
+			'{
2701 2701
 			(				# wrap whole match in $1
2702 2702
 			  !\[
2703 2703
 				(' . $this->nested_brackets_re . ')		# alt text = $2
@@ -2712,16 +2712,16 @@  discard block
 block discarded – undo
2712 2712
 
2713 2713
 			)
2714 2714
 			}xs',
2715
-            array(&$this, '_doImages_reference_callback'),
2716
-            $text
2717
-        );
2718
-
2719
-        #
2720
-        # Next, handle inline images:  ![alt text](url "optional title")
2721
-        # Don't forget: encode * and _
2722
-        #
2723
-        $text = preg_replace_callback(
2724
-            '{
2715
+			array(&$this, '_doImages_reference_callback'),
2716
+			$text
2717
+		);
2718
+
2719
+		#
2720
+		# Next, handle inline images:  ![alt text](url "optional title")
2721
+		# Don't forget: encode * and _
2722
+		#
2723
+		$text = preg_replace_callback(
2724
+			'{
2725 2725
 			(				# wrap whole match in $1
2726 2726
 			  !\[
2727 2727
 				(' . $this->nested_brackets_re . ')		# alt text = $2
@@ -2745,97 +2745,97 @@  discard block
 block discarded – undo
2745 2745
 			  (?:[ ]? ' . $this->id_class_attr_catch_re . ' )?	 # $8 = id/class attributes
2746 2746
 			)
2747 2747
 			}xs',
2748
-            array(&$this, '_doImages_inline_callback'),
2749
-            $text
2750
-        );
2751
-
2752
-        return $text;
2753
-    }
2754
-
2755
-    function _doImages_reference_callback($matches)
2756
-    {
2757
-        $whole_match = $matches[1];
2758
-        $alt_text    = $matches[2];
2759
-        $link_id     = strtolower($matches[3]);
2760
-
2761
-        if ($link_id == "") {
2762
-            $link_id = strtolower($alt_text); # for shortcut links like ![this][].
2763
-        }
2764
-
2765
-        $alt_text = $this->encodeAttribute($alt_text);
2766
-        if (isset($this->urls[$link_id])) {
2767
-            $url    = $this->encodeAttribute($this->urls[$link_id]);
2768
-            $result = "<img src=\"$url\" alt=\"$alt_text\"";
2769
-            if (isset($this->titles[$link_id])) {
2770
-                $title = $this->titles[$link_id];
2771
-                $title = $this->encodeAttribute($title);
2772
-                $result .= " title=\"$title\"";
2773
-            }
2774
-            if (isset($this->ref_attr[$link_id])) {
2775
-                $result .= $this->ref_attr[$link_id];
2776
-            }
2777
-            $result .= $this->empty_element_suffix;
2778
-            $result = $this->hashPart($result);
2779
-        } else {
2780
-            # If there's no such link ID, leave intact:
2781
-            $result = $whole_match;
2782
-        }
2783
-
2784
-        return $result;
2785
-    }
2786
-
2787
-    function _doImages_inline_callback($matches)
2788
-    {
2789
-        $whole_match = $matches[1];
2790
-        $alt_text    = $matches[2];
2791
-        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
2792
-        $title       =& $matches[7];
2793
-        $attr        = $this->doExtraAttributes("img", $dummy =& $matches[8]);
2794
-
2795
-        $alt_text = $this->encodeAttribute($alt_text);
2796
-        $url      = $this->encodeAttribute($url);
2797
-        $result   = "<img src=\"$url\" alt=\"$alt_text\"";
2798
-        if (isset($title)) {
2799
-            $title = $this->encodeAttribute($title);
2800
-            $result .= " title=\"$title\""; # $title already quoted
2801
-        }
2802
-        $result .= $attr;
2803
-        $result .= $this->empty_element_suffix;
2804
-
2805
-        return $this->hashPart($result);
2806
-    }
2807
-
2808
-    function doHeaders($text)
2809
-    {
2810
-        #
2811
-        # Redefined to add id and class attribute support.
2812
-        #
2813
-        # Setext-style headers:
2814
-        #	  Header 1  {#header1}
2815
-        #	  ========
2816
-        #
2817
-        #	  Header 2  {#header2 .class1 .class2}
2818
-        #	  --------
2819
-        #
2820
-        $text = preg_replace_callback(
2821
-            '{
2748
+			array(&$this, '_doImages_inline_callback'),
2749
+			$text
2750
+		);
2751
+
2752
+		return $text;
2753
+	}
2754
+
2755
+	function _doImages_reference_callback($matches)
2756
+	{
2757
+		$whole_match = $matches[1];
2758
+		$alt_text    = $matches[2];
2759
+		$link_id     = strtolower($matches[3]);
2760
+
2761
+		if ($link_id == "") {
2762
+			$link_id = strtolower($alt_text); # for shortcut links like ![this][].
2763
+		}
2764
+
2765
+		$alt_text = $this->encodeAttribute($alt_text);
2766
+		if (isset($this->urls[$link_id])) {
2767
+			$url    = $this->encodeAttribute($this->urls[$link_id]);
2768
+			$result = "<img src=\"$url\" alt=\"$alt_text\"";
2769
+			if (isset($this->titles[$link_id])) {
2770
+				$title = $this->titles[$link_id];
2771
+				$title = $this->encodeAttribute($title);
2772
+				$result .= " title=\"$title\"";
2773
+			}
2774
+			if (isset($this->ref_attr[$link_id])) {
2775
+				$result .= $this->ref_attr[$link_id];
2776
+			}
2777
+			$result .= $this->empty_element_suffix;
2778
+			$result = $this->hashPart($result);
2779
+		} else {
2780
+			# If there's no such link ID, leave intact:
2781
+			$result = $whole_match;
2782
+		}
2783
+
2784
+		return $result;
2785
+	}
2786
+
2787
+	function _doImages_inline_callback($matches)
2788
+	{
2789
+		$whole_match = $matches[1];
2790
+		$alt_text    = $matches[2];
2791
+		$url         = $matches[3] == '' ? $matches[4] : $matches[3];
2792
+		$title       =& $matches[7];
2793
+		$attr        = $this->doExtraAttributes("img", $dummy =& $matches[8]);
2794
+
2795
+		$alt_text = $this->encodeAttribute($alt_text);
2796
+		$url      = $this->encodeAttribute($url);
2797
+		$result   = "<img src=\"$url\" alt=\"$alt_text\"";
2798
+		if (isset($title)) {
2799
+			$title = $this->encodeAttribute($title);
2800
+			$result .= " title=\"$title\""; # $title already quoted
2801
+		}
2802
+		$result .= $attr;
2803
+		$result .= $this->empty_element_suffix;
2804
+
2805
+		return $this->hashPart($result);
2806
+	}
2807
+
2808
+	function doHeaders($text)
2809
+	{
2810
+		#
2811
+		# Redefined to add id and class attribute support.
2812
+		#
2813
+		# Setext-style headers:
2814
+		#	  Header 1  {#header1}
2815
+		#	  ========
2816
+		#
2817
+		#	  Header 2  {#header2 .class1 .class2}
2818
+		#	  --------
2819
+		#
2820
+		$text = preg_replace_callback(
2821
+			'{
2822 2822
 				(^.+?)								# $1: Header text
2823 2823
 				(?:[ ]+ ' . $this->id_class_attr_catch_re . ' )?	 # $3 = id/class attributes
2824 2824
 				[ ]*\n(=+|-+)[ ]*\n+				# $3: Header footer
2825 2825
 			}mx',
2826
-            array(&$this, '_doHeaders_callback_setext'),
2827
-            $text
2828
-        );
2829
-
2830
-        # atx-style headers:
2831
-        #	# Header 1        {#header1}
2832
-        #	## Header 2       {#header2}
2833
-        #	## Header 2 with closing hashes ##  {#header3.class1.class2}
2834
-        #	...
2835
-        #	###### Header 6   {.class2}
2836
-        #
2837
-        $text = preg_replace_callback(
2838
-            '{
2826
+			array(&$this, '_doHeaders_callback_setext'),
2827
+			$text
2828
+		);
2829
+
2830
+		# atx-style headers:
2831
+		#	# Header 1        {#header1}
2832
+		#	## Header 2       {#header2}
2833
+		#	## Header 2 with closing hashes ##  {#header3.class1.class2}
2834
+		#	...
2835
+		#	###### Header 6   {.class2}
2836
+		#
2837
+		$text = preg_replace_callback(
2838
+			'{
2839 2839
 				^(\#{1,6})	# $1 = string of #\'s
2840 2840
 				[ ]*
2841 2841
 				(.+?)		# $2 = Header text
@@ -2845,48 +2845,48 @@  discard block
 block discarded – undo
2845 2845
 				[ ]*
2846 2846
 				\n+
2847 2847
 			}xm',
2848
-            array(&$this, '_doHeaders_callback_atx'),
2849
-            $text
2850
-        );
2851
-
2852
-        return $text;
2853
-    }
2854
-
2855
-    function _doHeaders_callback_setext($matches)
2856
-    {
2857
-        if ($matches[3] == '-' && preg_match('{^- }', $matches[1])) {
2858
-            return $matches[0];
2859
-        }
2860
-        $level = $matches[3]{0} == '=' ? 1 : 2;
2861
-        $attr  = $this->doExtraAttributes("h$level", $dummy =& $matches[2]);
2862
-        $block = "<h$level$attr>" . $this->runSpanGamut($matches[1]) . "</h$level>";
2863
-        return "\n" . $this->hashBlock($block) . "\n\n";
2864
-    }
2865
-
2866
-    function _doHeaders_callback_atx($matches)
2867
-    {
2868
-        $level = strlen($matches[1]);
2869
-        $attr  = $this->doExtraAttributes("h$level", $dummy =& $matches[3]);
2870
-        $block = "<h$level$attr>" . $this->runSpanGamut($matches[2]) . "</h$level>";
2871
-        return "\n" . $this->hashBlock($block) . "\n\n";
2872
-    }
2873
-
2874
-    function doTables($text)
2875
-    {
2876
-        #
2877
-        # Form HTML tables.
2878
-        #
2879
-        $less_than_tab = $this->tab_width - 1;
2880
-        #
2881
-        # Find tables with leading pipe.
2882
-        #
2883
-        #	| Header 1 | Header 2
2884
-        #	| -------- | --------
2885
-        #	| Cell 1   | Cell 2
2886
-        #	| Cell 3   | Cell 4
2887
-        #
2888
-        $text = preg_replace_callback(
2889
-            '
2848
+			array(&$this, '_doHeaders_callback_atx'),
2849
+			$text
2850
+		);
2851
+
2852
+		return $text;
2853
+	}
2854
+
2855
+	function _doHeaders_callback_setext($matches)
2856
+	{
2857
+		if ($matches[3] == '-' && preg_match('{^- }', $matches[1])) {
2858
+			return $matches[0];
2859
+		}
2860
+		$level = $matches[3]{0} == '=' ? 1 : 2;
2861
+		$attr  = $this->doExtraAttributes("h$level", $dummy =& $matches[2]);
2862
+		$block = "<h$level$attr>" . $this->runSpanGamut($matches[1]) . "</h$level>";
2863
+		return "\n" . $this->hashBlock($block) . "\n\n";
2864
+	}
2865
+
2866
+	function _doHeaders_callback_atx($matches)
2867
+	{
2868
+		$level = strlen($matches[1]);
2869
+		$attr  = $this->doExtraAttributes("h$level", $dummy =& $matches[3]);
2870
+		$block = "<h$level$attr>" . $this->runSpanGamut($matches[2]) . "</h$level>";
2871
+		return "\n" . $this->hashBlock($block) . "\n\n";
2872
+	}
2873
+
2874
+	function doTables($text)
2875
+	{
2876
+		#
2877
+		# Form HTML tables.
2878
+		#
2879
+		$less_than_tab = $this->tab_width - 1;
2880
+		#
2881
+		# Find tables with leading pipe.
2882
+		#
2883
+		#	| Header 1 | Header 2
2884
+		#	| -------- | --------
2885
+		#	| Cell 1   | Cell 2
2886
+		#	| Cell 3   | Cell 4
2887
+		#
2888
+		$text = preg_replace_callback(
2889
+			'
2890 2890
 			{
2891 2891
 				^							# Start of a line
2892 2892
 				[ ]{0,' . $less_than_tab . '}	# Allowed whitespace.
@@ -2904,20 +2904,20 @@  discard block
 block discarded – undo
2904 2904
 				)
2905 2905
 				(?=\n|\Z)					# Stop at final double newline.
2906 2906
 			}xm',
2907
-            array(&$this, '_doTable_leadingPipe_callback'),
2908
-            $text
2909
-        );
2910
-
2911
-        #
2912
-        # Find tables without leading pipe.
2913
-        #
2914
-        #	Header 1 | Header 2
2915
-        #	-------- | --------
2916
-        #	Cell 1   | Cell 2
2917
-        #	Cell 3   | Cell 4
2918
-        #
2919
-        $text = preg_replace_callback(
2920
-            '
2907
+			array(&$this, '_doTable_leadingPipe_callback'),
2908
+			$text
2909
+		);
2910
+
2911
+		#
2912
+		# Find tables without leading pipe.
2913
+		#
2914
+		#	Header 1 | Header 2
2915
+		#	-------- | --------
2916
+		#	Cell 1   | Cell 2
2917
+		#	Cell 3   | Cell 4
2918
+		#
2919
+		$text = preg_replace_callback(
2920
+			'
2921 2921
 			{
2922 2922
 				^							# Start of a line
2923 2923
 				[ ]{0,' . $less_than_tab . '}	# Allowed whitespace.
@@ -2933,101 +2933,101 @@  discard block
 block discarded – undo
2933 2933
 				)
2934 2934
 				(?=\n|\Z)					# Stop at final double newline.
2935 2935
 			}xm',
2936
-            array(&$this, '_DoTable_callback'),
2937
-            $text
2938
-        );
2939
-
2940
-        return $text;
2941
-    }
2942
-
2943
-    function _doTable_leadingPipe_callback($matches)
2944
-    {
2945
-        $head      = $matches[1];
2946
-        $underline = $matches[2];
2947
-        $content   = $matches[3];
2948
-
2949
-        # Remove leading pipe for each row.
2950
-        $content = preg_replace('/^ *[|]/m', '', $content);
2951
-
2952
-        return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
2953
-    }
2954
-
2955
-    function _doTable_callback($matches)
2956
-    {
2957
-        $head      = $matches[1];
2958
-        $underline = $matches[2];
2959
-        $content   = $matches[3];
2960
-
2961
-        # Remove any tailing pipes for each line.
2962
-        $head      = preg_replace('/[|] *$/m', '', $head);
2963
-        $underline = preg_replace('/[|] *$/m', '', $underline);
2964
-        $content   = preg_replace('/[|] *$/m', '', $content);
2965
-
2966
-        # Reading alignement from header underline.
2967
-        $separators = preg_split('/ *[|] */', $underline);
2968
-        foreach ($separators as $n => $s) {
2969
-            if (preg_match('/^ *-+: *$/', $s)) {
2970
-                $attr[$n] = ' align="right"';
2971
-            } else if (preg_match('/^ *:-+: *$/', $s)) {
2972
-                $attr[$n] = ' align="center"';
2973
-            } else if (preg_match('/^ *:-+ *$/', $s)) {
2974
-                $attr[$n] = ' align="left"';
2975
-            } else {
2976
-                $attr[$n] = '';
2977
-            }
2978
-        }
2979
-
2980
-        # Parsing span elements, including code spans, character escapes,
2981
-        # and inline HTML tags, so that pipes inside those gets ignored.
2982
-        $head      = $this->parseSpan($head);
2983
-        $headers   = preg_split('/ *[|] */', $head);
2984
-        $col_count = count($headers);
2985
-        $attr      = array_pad($attr, $col_count, '');
2986
-
2987
-        # Write column headers.
2988
-        $text = "<table>\n";
2989
-        $text .= "<thead>\n";
2990
-        $text .= "<tr>\n";
2991
-        foreach ($headers as $n => $header) {
2992
-            $text .= "  <th$attr[$n]>" . $this->runSpanGamut(trim($header)) . "</th>\n";
2993
-        }
2994
-        $text .= "</tr>\n";
2995
-        $text .= "</thead>\n";
2996
-
2997
-        # Split content by row.
2998
-        $rows = explode("\n", trim($content, "\n"));
2999
-
3000
-        $text .= "<tbody>\n";
3001
-        foreach ($rows as $row) {
3002
-            # Parsing span elements, including code spans, character escapes,
3003
-            # and inline HTML tags, so that pipes inside those gets ignored.
3004
-            $row = $this->parseSpan($row);
3005
-
3006
-            # Split row by cell.
3007
-            $row_cells = preg_split('/ *[|] */', $row, $col_count);
3008
-            $row_cells = array_pad($row_cells, $col_count, '');
3009
-
3010
-            $text .= "<tr>\n";
3011
-            foreach ($row_cells as $n => $cell) {
3012
-                $text .= "  <td$attr[$n]>" . $this->runSpanGamut(trim($cell)) . "</td>\n";
3013
-            }
3014
-            $text .= "</tr>\n";
3015
-        }
3016
-        $text .= "</tbody>\n";
3017
-        $text .= "</table>";
3018
-
3019
-        return $this->hashBlock($text) . "\n";
3020
-    }
3021
-
3022
-    function doDefLists($text)
3023
-    {
3024
-        #
3025
-        # Form HTML definition lists.
3026
-        #
3027
-        $less_than_tab = $this->tab_width - 1;
3028
-
3029
-        # Re-usable pattern to match any entire dl list:
3030
-        $whole_list_re = '(?>
2936
+			array(&$this, '_DoTable_callback'),
2937
+			$text
2938
+		);
2939
+
2940
+		return $text;
2941
+	}
2942
+
2943
+	function _doTable_leadingPipe_callback($matches)
2944
+	{
2945
+		$head      = $matches[1];
2946
+		$underline = $matches[2];
2947
+		$content   = $matches[3];
2948
+
2949
+		# Remove leading pipe for each row.
2950
+		$content = preg_replace('/^ *[|]/m', '', $content);
2951
+
2952
+		return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
2953
+	}
2954
+
2955
+	function _doTable_callback($matches)
2956
+	{
2957
+		$head      = $matches[1];
2958
+		$underline = $matches[2];
2959
+		$content   = $matches[3];
2960
+
2961
+		# Remove any tailing pipes for each line.
2962
+		$head      = preg_replace('/[|] *$/m', '', $head);
2963
+		$underline = preg_replace('/[|] *$/m', '', $underline);
2964
+		$content   = preg_replace('/[|] *$/m', '', $content);
2965
+
2966
+		# Reading alignement from header underline.
2967
+		$separators = preg_split('/ *[|] */', $underline);
2968
+		foreach ($separators as $n => $s) {
2969
+			if (preg_match('/^ *-+: *$/', $s)) {
2970
+				$attr[$n] = ' align="right"';
2971
+			} else if (preg_match('/^ *:-+: *$/', $s)) {
2972
+				$attr[$n] = ' align="center"';
2973
+			} else if (preg_match('/^ *:-+ *$/', $s)) {
2974
+				$attr[$n] = ' align="left"';
2975
+			} else {
2976
+				$attr[$n] = '';
2977
+			}
2978
+		}
2979
+
2980
+		# Parsing span elements, including code spans, character escapes,
2981
+		# and inline HTML tags, so that pipes inside those gets ignored.
2982
+		$head      = $this->parseSpan($head);
2983
+		$headers   = preg_split('/ *[|] */', $head);
2984
+		$col_count = count($headers);
2985
+		$attr      = array_pad($attr, $col_count, '');
2986
+
2987
+		# Write column headers.
2988
+		$text = "<table>\n";
2989
+		$text .= "<thead>\n";
2990
+		$text .= "<tr>\n";
2991
+		foreach ($headers as $n => $header) {
2992
+			$text .= "  <th$attr[$n]>" . $this->runSpanGamut(trim($header)) . "</th>\n";
2993
+		}
2994
+		$text .= "</tr>\n";
2995
+		$text .= "</thead>\n";
2996
+
2997
+		# Split content by row.
2998
+		$rows = explode("\n", trim($content, "\n"));
2999
+
3000
+		$text .= "<tbody>\n";
3001
+		foreach ($rows as $row) {
3002
+			# Parsing span elements, including code spans, character escapes,
3003
+			# and inline HTML tags, so that pipes inside those gets ignored.
3004
+			$row = $this->parseSpan($row);
3005
+
3006
+			# Split row by cell.
3007
+			$row_cells = preg_split('/ *[|] */', $row, $col_count);
3008
+			$row_cells = array_pad($row_cells, $col_count, '');
3009
+
3010
+			$text .= "<tr>\n";
3011
+			foreach ($row_cells as $n => $cell) {
3012
+				$text .= "  <td$attr[$n]>" . $this->runSpanGamut(trim($cell)) . "</td>\n";
3013
+			}
3014
+			$text .= "</tr>\n";
3015
+		}
3016
+		$text .= "</tbody>\n";
3017
+		$text .= "</table>";
3018
+
3019
+		return $this->hashBlock($text) . "\n";
3020
+	}
3021
+
3022
+	function doDefLists($text)
3023
+	{
3024
+		#
3025
+		# Form HTML definition lists.
3026
+		#
3027
+		$less_than_tab = $this->tab_width - 1;
3028
+
3029
+		# Re-usable pattern to match any entire dl list:
3030
+		$whole_list_re = '(?>
3031 3031
 			(								# $1 = whole list
3032 3032
 			  (								# $2
3033 3033
 				[ ]{0,' . $less_than_tab . '}
@@ -3054,44 +3054,44 @@  discard block
 block discarded – undo
3054 3054
 			)
3055 3055
 		)'; // mx
3056 3056
 
3057
-        $text = preg_replace_callback(
3058
-            '{
3057
+		$text = preg_replace_callback(
3058
+			'{
3059 3059
 				(?>\A\n?|(?<=\n\n))
3060 3060
 				' . $whole_list_re . '
3061 3061
 			}mx',
3062
-            array(&$this, '_doDefLists_callback'),
3063
-            $text
3064
-        );
3065
-
3066
-        return $text;
3067
-    }
3068
-
3069
-    function _doDefLists_callback($matches)
3070
-    {
3071
-        # Re-usable patterns to match list item bullets and number markers:
3072
-        $list = $matches[1];
3073
-
3074
-        # Turn double returns into triple returns, so that we can make a
3075
-        # paragraph for the last item in a list, if necessary:
3076
-        $result = trim($this->processDefListItems($list));
3077
-        $result = "<dl>\n" . $result . "\n</dl>";
3078
-        return $this->hashBlock($result) . "\n\n";
3079
-    }
3080
-
3081
-    function processDefListItems($list_str)
3082
-    {
3083
-        #
3084
-        #	Process the contents of a single definition list, splitting it
3085
-        #	into individual term and definition list items.
3086
-        #
3087
-        $less_than_tab = $this->tab_width - 1;
3088
-
3089
-        # trim trailing blank lines:
3090
-        $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
3091
-
3092
-        # Process definition terms.
3093
-        $list_str = preg_replace_callback(
3094
-            '{
3062
+			array(&$this, '_doDefLists_callback'),
3063
+			$text
3064
+		);
3065
+
3066
+		return $text;
3067
+	}
3068
+
3069
+	function _doDefLists_callback($matches)
3070
+	{
3071
+		# Re-usable patterns to match list item bullets and number markers:
3072
+		$list = $matches[1];
3073
+
3074
+		# Turn double returns into triple returns, so that we can make a
3075
+		# paragraph for the last item in a list, if necessary:
3076
+		$result = trim($this->processDefListItems($list));
3077
+		$result = "<dl>\n" . $result . "\n</dl>";
3078
+		return $this->hashBlock($result) . "\n\n";
3079
+	}
3080
+
3081
+	function processDefListItems($list_str)
3082
+	{
3083
+		#
3084
+		#	Process the contents of a single definition list, splitting it
3085
+		#	into individual term and definition list items.
3086
+		#
3087
+		$less_than_tab = $this->tab_width - 1;
3088
+
3089
+		# trim trailing blank lines:
3090
+		$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
3091
+
3092
+		# Process definition terms.
3093
+		$list_str = preg_replace_callback(
3094
+			'{
3095 3095
 			(?>\A\n?|\n\n+)					# leading line
3096 3096
 			(								# definition terms = $1
3097 3097
 				[ ]{0,' . $less_than_tab . '}	# leading whitespace
@@ -3102,13 +3102,13 @@  discard block
 block discarded – undo
3102 3102
 			(?=\n?[ ]{0,3}:[ ])				# lookahead for following line feed
3103 3103
 											#   with a definition mark.
3104 3104
 			}xm',
3105
-            array(&$this, '_processDefListItems_callback_dt'),
3106
-            $list_str
3107
-        );
3105
+			array(&$this, '_processDefListItems_callback_dt'),
3106
+			$list_str
3107
+		);
3108 3108
 
3109
-        # Process actual definitions.
3110
-        $list_str = preg_replace_callback(
3111
-            '{
3109
+		# Process actual definitions.
3110
+		$list_str = preg_replace_callback(
3111
+			'{
3112 3112
 			\n(\n+)?						# leading line = $1
3113 3113
 			(								# marker space = $2
3114 3114
 				[ ]{0,' . $less_than_tab . '}	# whitespace before colon
@@ -3122,56 +3122,56 @@  discard block
 block discarded – undo
3122 3122
 				)
3123 3123
 			)
3124 3124
 			}xm',
3125
-            array(&$this, '_processDefListItems_callback_dd'),
3126
-            $list_str
3127
-        );
3128
-
3129
-        return $list_str;
3130
-    }
3131
-
3132
-    function _processDefListItems_callback_dt($matches)
3133
-    {
3134
-        $terms = explode("\n", trim($matches[1]));
3135
-        $text  = '';
3136
-        foreach ($terms as $term) {
3137
-            $term = $this->runSpanGamut(trim($term));
3138
-            $text .= "\n<dt>" . $term . "</dt>";
3139
-        }
3140
-        return $text . "\n";
3141
-    }
3142
-
3143
-    function _processDefListItems_callback_dd($matches)
3144
-    {
3145
-        $leading_line = $matches[1];
3146
-        $marker_space = $matches[2];
3147
-        $def          = $matches[3];
3148
-
3149
-        if ($leading_line || preg_match('/\n{2,}/', $def)) {
3150
-            # Replace marker with the appropriate whitespace indentation
3151
-            $def = str_repeat(' ', strlen($marker_space)) . $def;
3152
-            $def = $this->runBlockGamut($this->outdent($def . "\n\n"));
3153
-            $def = "\n" . $def . "\n";
3154
-        } else {
3155
-            $def = rtrim($def);
3156
-            $def = $this->runSpanGamut($this->outdent($def));
3157
-        }
3158
-
3159
-        return "\n<dd>" . $def . "</dd>\n";
3160
-    }
3161
-
3162
-    function doFencedCodeBlocks($text)
3163
-    {
3164
-        #
3165
-        # Adding the fenced code block syntax to regular Markdown:
3166
-        #
3167
-        # ~~~
3168
-        # Code block
3169
-        # ~~~
3170
-        #
3171
-        $less_than_tab = $this->tab_width;
3172
-
3173
-        $text = preg_replace_callback(
3174
-            '{
3125
+			array(&$this, '_processDefListItems_callback_dd'),
3126
+			$list_str
3127
+		);
3128
+
3129
+		return $list_str;
3130
+	}
3131
+
3132
+	function _processDefListItems_callback_dt($matches)
3133
+	{
3134
+		$terms = explode("\n", trim($matches[1]));
3135
+		$text  = '';
3136
+		foreach ($terms as $term) {
3137
+			$term = $this->runSpanGamut(trim($term));
3138
+			$text .= "\n<dt>" . $term . "</dt>";
3139
+		}
3140
+		return $text . "\n";
3141
+	}
3142
+
3143
+	function _processDefListItems_callback_dd($matches)
3144
+	{
3145
+		$leading_line = $matches[1];
3146
+		$marker_space = $matches[2];
3147
+		$def          = $matches[3];
3148
+
3149
+		if ($leading_line || preg_match('/\n{2,}/', $def)) {
3150
+			# Replace marker with the appropriate whitespace indentation
3151
+			$def = str_repeat(' ', strlen($marker_space)) . $def;
3152
+			$def = $this->runBlockGamut($this->outdent($def . "\n\n"));
3153
+			$def = "\n" . $def . "\n";
3154
+		} else {
3155
+			$def = rtrim($def);
3156
+			$def = $this->runSpanGamut($this->outdent($def));
3157
+		}
3158
+
3159
+		return "\n<dd>" . $def . "</dd>\n";
3160
+	}
3161
+
3162
+	function doFencedCodeBlocks($text)
3163
+	{
3164
+		#
3165
+		# Adding the fenced code block syntax to regular Markdown:
3166
+		#
3167
+		# ~~~
3168
+		# Code block
3169
+		# ~~~
3170
+		#
3171
+		$less_than_tab = $this->tab_width;
3172
+
3173
+		$text = preg_replace_callback(
3174
+			'{
3175 3175
 				(?:\n|\A)
3176 3176
 				# 1: Opening marker
3177 3177
 				(
@@ -3196,120 +3196,120 @@  discard block
 block discarded – undo
3196 3196
 				# Closing marker.
3197 3197
 				\1 [ ]* \n
3198 3198
 			}xm',
3199
-            array(&$this, '_doFencedCodeBlocks_callback'),
3200
-            $text
3201
-        );
3202
-
3203
-        return $text;
3204
-    }
3205
-
3206
-    function _doFencedCodeBlocks_callback($matches)
3207
-    {
3208
-        $classname =& $matches[2];
3209
-        $attrs     =& $matches[3];
3210
-        $codeblock = $matches[4];
3211
-        $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
3212
-        $codeblock = preg_replace_callback(
3213
-            '/^\n+/',
3214
-            array(&$this, '_doFencedCodeBlocks_newlines'),
3215
-            $codeblock
3216
-        );
3217
-
3218
-        if ($classname != "") {
3219
-            if ($classname{0} == '.') {
3220
-                $classname = substr($classname, 1);
3221
-            }
3222
-            $attr_str = ' class="' . $this->code_class_prefix . $classname . '"';
3223
-        } else {
3224
-            $attr_str = $this->doExtraAttributes($this->code_attr_on_pre ? "pre" : "code", $attrs);
3225
-        }
3226
-        $pre_attr_str  = $this->code_attr_on_pre ? $attr_str : '';
3227
-        $code_attr_str = $this->code_attr_on_pre ? '' : $attr_str;
3228
-        $codeblock     = "<pre$pre_attr_str><code$code_attr_str>$codeblock</code></pre>";
3229
-
3230
-        return "\n\n" . $this->hashBlock($codeblock) . "\n\n";
3231
-    }
3232
-
3233
-    function _doFencedCodeBlocks_newlines($matches)
3234
-    {
3235
-        return str_repeat(
3236
-            "<br$this->empty_element_suffix",
3237
-            strlen($matches[0])
3238
-        );
3239
-    }
3240
-
3241
-
3242
-    #
3243
-    # Redefining emphasis markers so that emphasis by underscore does not
3244
-    # work in the middle of a word.
3245
-    #
3246
-    var $em_relist = array(
3247
-        ''  => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S|$)(?![\.,:;]\s)',
3248
-        '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
3249
-        '_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
3250
-    );
3251
-
3252
-    var $strong_relist = array(
3253
-        ''   => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![\.,:;]\s)',
3254
-        '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
3255
-        '__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
3256
-    );
3257
-
3258
-    var $em_strong_relist = array(
3259
-        ''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![\.,:;]\s)',
3260
-        '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
3261
-        '___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
3262
-    );
3263
-
3264
-    function formParagraphs($text)
3265
-    {
3266
-        #
3267
-        #	Params:
3268
-        #		$text - string to process with html <p> tags
3269
-        #
3270
-        # Strip leading and trailing lines:
3271
-        $text = preg_replace('/\A\n+|\n+\z/', '', $text);
3272
-
3273
-        $grafs = preg_split('/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY);
3274
-
3275
-        #
3276
-        # Wrap <p> tags and unhashify HTML blocks
3277
-        #
3278
-        foreach ($grafs as $key => $value) {
3279
-            $value = trim($this->runSpanGamut($value));
3280
-
3281
-            # Check if this should be enclosed in a paragraph.
3282
-            # Clean tag hashes & block tag hashes are left alone.
3283
-            $is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
3284
-
3285
-            if ($is_p) {
3286
-                $value = "<p>$value</p>";
3287
-            }
3288
-            $grafs[$key] = $value;
3289
-        }
3290
-
3291
-        # Join grafs in one text, then unhash HTML tags.
3292
-        $text = implode("\n\n", $grafs);
3293
-
3294
-        # Finish by removing any tag hashes still present in $text.
3295
-        $text = $this->unhash($text);
3296
-
3297
-        return $text;
3298
-    }
3299
-
3300
-    ### Footnotes
3301
-
3302
-    function stripFootnotes($text)
3303
-    {
3304
-        #
3305
-        # Strips link definitions from text, stores the URLs and titles in
3306
-        # hash references.
3307
-        #
3308
-        $less_than_tab = $this->tab_width - 1;
3309
-
3310
-        # Link defs are in the form: [^id]: url "optional title"
3311
-        $text = preg_replace_callback(
3312
-            '{
3199
+			array(&$this, '_doFencedCodeBlocks_callback'),
3200
+			$text
3201
+		);
3202
+
3203
+		return $text;
3204
+	}
3205
+
3206
+	function _doFencedCodeBlocks_callback($matches)
3207
+	{
3208
+		$classname =& $matches[2];
3209
+		$attrs     =& $matches[3];
3210
+		$codeblock = $matches[4];
3211
+		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
3212
+		$codeblock = preg_replace_callback(
3213
+			'/^\n+/',
3214
+			array(&$this, '_doFencedCodeBlocks_newlines'),
3215
+			$codeblock
3216
+		);
3217
+
3218
+		if ($classname != "") {
3219
+			if ($classname{0} == '.') {
3220
+				$classname = substr($classname, 1);
3221
+			}
3222
+			$attr_str = ' class="' . $this->code_class_prefix . $classname . '"';
3223
+		} else {
3224
+			$attr_str = $this->doExtraAttributes($this->code_attr_on_pre ? "pre" : "code", $attrs);
3225
+		}
3226
+		$pre_attr_str  = $this->code_attr_on_pre ? $attr_str : '';
3227
+		$code_attr_str = $this->code_attr_on_pre ? '' : $attr_str;
3228
+		$codeblock     = "<pre$pre_attr_str><code$code_attr_str>$codeblock</code></pre>";
3229
+
3230
+		return "\n\n" . $this->hashBlock($codeblock) . "\n\n";
3231
+	}
3232
+
3233
+	function _doFencedCodeBlocks_newlines($matches)
3234
+	{
3235
+		return str_repeat(
3236
+			"<br$this->empty_element_suffix",
3237
+			strlen($matches[0])
3238
+		);
3239
+	}
3240
+
3241
+
3242
+	#
3243
+	# Redefining emphasis markers so that emphasis by underscore does not
3244
+	# work in the middle of a word.
3245
+	#
3246
+	var $em_relist = array(
3247
+		''  => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S|$)(?![\.,:;]\s)',
3248
+		'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
3249
+		'_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
3250
+	);
3251
+
3252
+	var $strong_relist = array(
3253
+		''   => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![\.,:;]\s)',
3254
+		'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
3255
+		'__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
3256
+	);
3257
+
3258
+	var $em_strong_relist = array(
3259
+		''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![\.,:;]\s)',
3260
+		'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
3261
+		'___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
3262
+	);
3263
+
3264
+	function formParagraphs($text)
3265
+	{
3266
+		#
3267
+		#	Params:
3268
+		#		$text - string to process with html <p> tags
3269
+		#
3270
+		# Strip leading and trailing lines:
3271
+		$text = preg_replace('/\A\n+|\n+\z/', '', $text);
3272
+
3273
+		$grafs = preg_split('/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY);
3274
+
3275
+		#
3276
+		# Wrap <p> tags and unhashify HTML blocks
3277
+		#
3278
+		foreach ($grafs as $key => $value) {
3279
+			$value = trim($this->runSpanGamut($value));
3280
+
3281
+			# Check if this should be enclosed in a paragraph.
3282
+			# Clean tag hashes & block tag hashes are left alone.
3283
+			$is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
3284
+
3285
+			if ($is_p) {
3286
+				$value = "<p>$value</p>";
3287
+			}
3288
+			$grafs[$key] = $value;
3289
+		}
3290
+
3291
+		# Join grafs in one text, then unhash HTML tags.
3292
+		$text = implode("\n\n", $grafs);
3293
+
3294
+		# Finish by removing any tag hashes still present in $text.
3295
+		$text = $this->unhash($text);
3296
+
3297
+		return $text;
3298
+	}
3299
+
3300
+	### Footnotes
3301
+
3302
+	function stripFootnotes($text)
3303
+	{
3304
+		#
3305
+		# Strips link definitions from text, stores the URLs and titles in
3306
+		# hash references.
3307
+		#
3308
+		$less_than_tab = $this->tab_width - 1;
3309
+
3310
+		# Link defs are in the form: [^id]: url "optional title"
3311
+		$text = preg_replace_callback(
3312
+			'{
3313 3313
 			^[ ]{0,' . $less_than_tab . '}\[\^(.+?)\][ ]?:	# note_id = $1
3314 3314
 			  [ ]*
3315 3315
 			  \n?					# maybe *one* newline
@@ -3324,215 +3324,215 @@  discard block
 block discarded – undo
3324 3324
 				)*
3325 3325
 			)
3326 3326
 			}xm',
3327
-            array(&$this, '_stripFootnotes_callback'),
3328
-            $text
3329
-        );
3330
-        return $text;
3331
-    }
3332
-
3333
-    function _stripFootnotes_callback($matches)
3334
-    {
3335
-        $note_id                   = $this->fn_id_prefix . $matches[1];
3336
-        $this->footnotes[$note_id] = $this->outdent($matches[2]);
3337
-        return ''; # String that will replace the block
3338
-    }
3339
-
3340
-    function doFootnotes($text)
3341
-    {
3342
-        #
3343
-        # Replace footnote references in $text [^id] with a special text-token
3344
-        # which will be replaced by the actual footnote marker in appendFootnotes.
3345
-        #
3346
-        if (!$this->in_anchor) {
3347
-            $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
3348
-        }
3349
-        return $text;
3350
-    }
3351
-
3352
-    function appendFootnotes($text)
3353
-    {
3354
-        #
3355
-        # Append footnote list to text.
3356
-        #
3357
-        $text = preg_replace_callback(
3358
-            '{F\x1Afn:(.*?)\x1A:}',
3359
-            array(&$this, '_appendFootnotes_callback'),
3360
-            $text
3361
-        );
3362
-
3363
-        if (!empty($this->footnotes_ordered)) {
3364
-            $text .= "\n\n";
3365
-            $text .= "<div class=\"footnotes\">\n";
3366
-            $text .= "<hr" . $this->empty_element_suffix . "\n";
3367
-            $text .= "<ol>\n\n";
3368
-
3369
-            $attr = " rev=\"footnote\"";
3370
-            if ($this->fn_backlink_class != "") {
3371
-                $class = $this->fn_backlink_class;
3372
-                $class = $this->encodeAttribute($class);
3373
-                $attr .= " class=\"$class\"";
3374
-            }
3375
-            if ($this->fn_backlink_title != "") {
3376
-                $title = $this->fn_backlink_title;
3377
-                $title = $this->encodeAttribute($title);
3378
-                $attr .= " title=\"$title\"";
3379
-            }
3380
-            $num = 0;
3381
-
3382
-            while (!empty($this->footnotes_ordered)) {
3383
-                $footnote = reset($this->footnotes_ordered);
3384
-                $note_id  = key($this->footnotes_ordered);
3385
-                unset($this->footnotes_ordered[$note_id]);
3386
-                $ref_count = $this->footnotes_ref_count[$note_id];
3387
-                unset($this->footnotes_ref_count[$note_id]);
3388
-                unset($this->footnotes[$note_id]);
3389
-
3390
-                $footnote .= "\n"; # Need to append newline before parsing.
3391
-                $footnote = $this->runBlockGamut("$footnote\n");
3392
-                $footnote = preg_replace_callback(
3393
-                    '{F\x1Afn:(.*?)\x1A:}',
3394
-                    array(&$this, '_appendFootnotes_callback'),
3395
-                    $footnote
3396
-                );
3397
-
3398
-                $attr    = str_replace("%%", ++ $num, $attr);
3399
-                $note_id = $this->encodeAttribute($note_id);
3400
-
3401
-                # Prepare backlink, multiple backlinks if multiple references
3402
-                $backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
3403
-                for ($ref_num = 2; $ref_num <= $ref_count; ++ $ref_num) {
3404
-                    $backlink .= " <a href=\"#fnref$ref_num:$note_id\"$attr>&#8617;</a>";
3405
-                }
3406
-                # Add backlink to last paragraph; create new paragraph if needed.
3407
-                if (preg_match('{</p>$}', $footnote)) {
3408
-                    $footnote = substr($footnote, 0, - 4) . "&#160;$backlink</p>";
3409
-                } else {
3410
-                    $footnote .= "\n\n<p>$backlink</p>";
3411
-                }
3412
-
3413
-                $text .= "<li id=\"fn:$note_id\">\n";
3414
-                $text .= $footnote . "\n";
3415
-                $text .= "</li>\n\n";
3416
-            }
3417
-
3418
-            $text .= "</ol>\n";
3419
-            $text .= "</div>";
3420
-        }
3421
-        return $text;
3422
-    }
3423
-
3424
-    function _appendFootnotes_callback($matches)
3425
-    {
3426
-        $node_id = $this->fn_id_prefix . $matches[1];
3427
-
3428
-        # Create footnote marker only if it has a corresponding footnote *and*
3429
-        # the footnote hasn't been used by another marker.
3430
-        if (isset($this->footnotes[$node_id])) {
3431
-            $num =& $this->footnotes_numbers[$node_id];
3432
-            if (!isset($num)) {
3433
-                # Transfer footnote content to the ordered list and give it its
3434
-                # number
3435
-                $this->footnotes_ordered[$node_id]   = $this->footnotes[$node_id];
3436
-                $this->footnotes_ref_count[$node_id] = 1;
3437
-                $num                                 = $this->footnote_counter ++;
3438
-                $ref_count_mark                      = '';
3439
-            } else {
3440
-                $ref_count_mark = $this->footnotes_ref_count[$node_id] += 1;
3441
-            }
3442
-
3443
-            $attr = " rel=\"footnote\"";
3444
-            if ($this->fn_link_class != "") {
3445
-                $class = $this->fn_link_class;
3446
-                $class = $this->encodeAttribute($class);
3447
-                $attr .= " class=\"$class\"";
3448
-            }
3449
-            if ($this->fn_link_title != "") {
3450
-                $title = $this->fn_link_title;
3451
-                $title = $this->encodeAttribute($title);
3452
-                $attr .= " title=\"$title\"";
3453
-            }
3454
-
3455
-            $attr    = str_replace("%%", $num, $attr);
3456
-            $node_id = $this->encodeAttribute($node_id);
3457
-
3458
-            return
3459
-                "<sup id=\"fnref$ref_count_mark:$node_id\">" .
3460
-                "<a href=\"#fn:$node_id\"$attr>$num</a>" .
3461
-                "</sup>";
3462
-        }
3463
-
3464
-        return "[^" . $matches[1] . "]";
3465
-    }
3466
-
3467
-    ### Abbreviations ###
3468
-
3469
-    function stripAbbreviations($text)
3470
-    {
3471
-        #
3472
-        # Strips abbreviations from text, stores titles in hash references.
3473
-        #
3474
-        $less_than_tab = $this->tab_width - 1;
3475
-
3476
-        # Link defs are in the form: [id]*: url "optional title"
3477
-        $text = preg_replace_callback(
3478
-            '{
3327
+			array(&$this, '_stripFootnotes_callback'),
3328
+			$text
3329
+		);
3330
+		return $text;
3331
+	}
3332
+
3333
+	function _stripFootnotes_callback($matches)
3334
+	{
3335
+		$note_id                   = $this->fn_id_prefix . $matches[1];
3336
+		$this->footnotes[$note_id] = $this->outdent($matches[2]);
3337
+		return ''; # String that will replace the block
3338
+	}
3339
+
3340
+	function doFootnotes($text)
3341
+	{
3342
+		#
3343
+		# Replace footnote references in $text [^id] with a special text-token
3344
+		# which will be replaced by the actual footnote marker in appendFootnotes.
3345
+		#
3346
+		if (!$this->in_anchor) {
3347
+			$text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
3348
+		}
3349
+		return $text;
3350
+	}
3351
+
3352
+	function appendFootnotes($text)
3353
+	{
3354
+		#
3355
+		# Append footnote list to text.
3356
+		#
3357
+		$text = preg_replace_callback(
3358
+			'{F\x1Afn:(.*?)\x1A:}',
3359
+			array(&$this, '_appendFootnotes_callback'),
3360
+			$text
3361
+		);
3362
+
3363
+		if (!empty($this->footnotes_ordered)) {
3364
+			$text .= "\n\n";
3365
+			$text .= "<div class=\"footnotes\">\n";
3366
+			$text .= "<hr" . $this->empty_element_suffix . "\n";
3367
+			$text .= "<ol>\n\n";
3368
+
3369
+			$attr = " rev=\"footnote\"";
3370
+			if ($this->fn_backlink_class != "") {
3371
+				$class = $this->fn_backlink_class;
3372
+				$class = $this->encodeAttribute($class);
3373
+				$attr .= " class=\"$class\"";
3374
+			}
3375
+			if ($this->fn_backlink_title != "") {
3376
+				$title = $this->fn_backlink_title;
3377
+				$title = $this->encodeAttribute($title);
3378
+				$attr .= " title=\"$title\"";
3379
+			}
3380
+			$num = 0;
3381
+
3382
+			while (!empty($this->footnotes_ordered)) {
3383
+				$footnote = reset($this->footnotes_ordered);
3384
+				$note_id  = key($this->footnotes_ordered);
3385
+				unset($this->footnotes_ordered[$note_id]);
3386
+				$ref_count = $this->footnotes_ref_count[$note_id];
3387
+				unset($this->footnotes_ref_count[$note_id]);
3388
+				unset($this->footnotes[$note_id]);
3389
+
3390
+				$footnote .= "\n"; # Need to append newline before parsing.
3391
+				$footnote = $this->runBlockGamut("$footnote\n");
3392
+				$footnote = preg_replace_callback(
3393
+					'{F\x1Afn:(.*?)\x1A:}',
3394
+					array(&$this, '_appendFootnotes_callback'),
3395
+					$footnote
3396
+				);
3397
+
3398
+				$attr    = str_replace("%%", ++ $num, $attr);
3399
+				$note_id = $this->encodeAttribute($note_id);
3400
+
3401
+				# Prepare backlink, multiple backlinks if multiple references
3402
+				$backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
3403
+				for ($ref_num = 2; $ref_num <= $ref_count; ++ $ref_num) {
3404
+					$backlink .= " <a href=\"#fnref$ref_num:$note_id\"$attr>&#8617;</a>";
3405
+				}
3406
+				# Add backlink to last paragraph; create new paragraph if needed.
3407
+				if (preg_match('{</p>$}', $footnote)) {
3408
+					$footnote = substr($footnote, 0, - 4) . "&#160;$backlink</p>";
3409
+				} else {
3410
+					$footnote .= "\n\n<p>$backlink</p>";
3411
+				}
3412
+
3413
+				$text .= "<li id=\"fn:$note_id\">\n";
3414
+				$text .= $footnote . "\n";
3415
+				$text .= "</li>\n\n";
3416
+			}
3417
+
3418
+			$text .= "</ol>\n";
3419
+			$text .= "</div>";
3420
+		}
3421
+		return $text;
3422
+	}
3423
+
3424
+	function _appendFootnotes_callback($matches)
3425
+	{
3426
+		$node_id = $this->fn_id_prefix . $matches[1];
3427
+
3428
+		# Create footnote marker only if it has a corresponding footnote *and*
3429
+		# the footnote hasn't been used by another marker.
3430
+		if (isset($this->footnotes[$node_id])) {
3431
+			$num =& $this->footnotes_numbers[$node_id];
3432
+			if (!isset($num)) {
3433
+				# Transfer footnote content to the ordered list and give it its
3434
+				# number
3435
+				$this->footnotes_ordered[$node_id]   = $this->footnotes[$node_id];
3436
+				$this->footnotes_ref_count[$node_id] = 1;
3437
+				$num                                 = $this->footnote_counter ++;
3438
+				$ref_count_mark                      = '';
3439
+			} else {
3440
+				$ref_count_mark = $this->footnotes_ref_count[$node_id] += 1;
3441
+			}
3442
+
3443
+			$attr = " rel=\"footnote\"";
3444
+			if ($this->fn_link_class != "") {
3445
+				$class = $this->fn_link_class;
3446
+				$class = $this->encodeAttribute($class);
3447
+				$attr .= " class=\"$class\"";
3448
+			}
3449
+			if ($this->fn_link_title != "") {
3450
+				$title = $this->fn_link_title;
3451
+				$title = $this->encodeAttribute($title);
3452
+				$attr .= " title=\"$title\"";
3453
+			}
3454
+
3455
+			$attr    = str_replace("%%", $num, $attr);
3456
+			$node_id = $this->encodeAttribute($node_id);
3457
+
3458
+			return
3459
+				"<sup id=\"fnref$ref_count_mark:$node_id\">" .
3460
+				"<a href=\"#fn:$node_id\"$attr>$num</a>" .
3461
+				"</sup>";
3462
+		}
3463
+
3464
+		return "[^" . $matches[1] . "]";
3465
+	}
3466
+
3467
+	### Abbreviations ###
3468
+
3469
+	function stripAbbreviations($text)
3470
+	{
3471
+		#
3472
+		# Strips abbreviations from text, stores titles in hash references.
3473
+		#
3474
+		$less_than_tab = $this->tab_width - 1;
3475
+
3476
+		# Link defs are in the form: [id]*: url "optional title"
3477
+		$text = preg_replace_callback(
3478
+			'{
3479 3479
 			^[ ]{0,' . $less_than_tab . '}\*\[(.+?)\][ ]?:	# abbr_id = $1
3480 3480
 			(.*)					# text = $2 (no blank lines allowed)
3481 3481
 			}xm',
3482
-            array(&$this, '_stripAbbreviations_callback'),
3483
-            $text
3484
-        );
3485
-        return $text;
3486
-    }
3487
-
3488
-    function _stripAbbreviations_callback($matches)
3489
-    {
3490
-        $abbr_word = $matches[1];
3491
-        $abbr_desc = $matches[2];
3492
-        if ($this->abbr_word_re) {
3493
-            $this->abbr_word_re .= '|';
3494
-        }
3495
-        $this->abbr_word_re .= preg_quote($abbr_word);
3496
-        $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
3497
-        return ''; # String that will replace the block
3498
-    }
3499
-
3500
-    function doAbbreviations($text)
3501
-    {
3502
-        #
3503
-        # Find defined abbreviations in text and wrap them in <abbr> elements.
3504
-        #
3505
-        if ($this->abbr_word_re) {
3506
-            // cannot use the /x modifier because abbr_word_re may
3507
-            // contain significant spaces:
3508
-            $text = preg_replace_callback(
3509
-                '{' .
3510
-                '(?<![\w\x1A])' .
3511
-                '(?:' . $this->abbr_word_re . ')' .
3512
-                '(?![\w\x1A])' .
3513
-                '}',
3514
-                array(&$this, '_doAbbreviations_callback'),
3515
-                $text
3516
-            );
3517
-        }
3518
-        return $text;
3519
-    }
3520
-
3521
-    function _doAbbreviations_callback($matches)
3522
-    {
3523
-        $abbr = $matches[0];
3524
-        if (isset($this->abbr_desciptions[$abbr])) {
3525
-            $desc = $this->abbr_desciptions[$abbr];
3526
-            if (empty($desc)) {
3527
-                return $this->hashPart("<abbr>$abbr</abbr>");
3528
-            } else {
3529
-                $desc = $this->encodeAttribute($desc);
3530
-                return $this->hashPart("<abbr title=\"$desc\">$abbr</abbr>");
3531
-            }
3532
-        } else {
3533
-            return $matches[0];
3534
-        }
3535
-    }
3482
+			array(&$this, '_stripAbbreviations_callback'),
3483
+			$text
3484
+		);
3485
+		return $text;
3486
+	}
3487
+
3488
+	function _stripAbbreviations_callback($matches)
3489
+	{
3490
+		$abbr_word = $matches[1];
3491
+		$abbr_desc = $matches[2];
3492
+		if ($this->abbr_word_re) {
3493
+			$this->abbr_word_re .= '|';
3494
+		}
3495
+		$this->abbr_word_re .= preg_quote($abbr_word);
3496
+		$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
3497
+		return ''; # String that will replace the block
3498
+	}
3499
+
3500
+	function doAbbreviations($text)
3501
+	{
3502
+		#
3503
+		# Find defined abbreviations in text and wrap them in <abbr> elements.
3504
+		#
3505
+		if ($this->abbr_word_re) {
3506
+			// cannot use the /x modifier because abbr_word_re may
3507
+			// contain significant spaces:
3508
+			$text = preg_replace_callback(
3509
+				'{' .
3510
+				'(?<![\w\x1A])' .
3511
+				'(?:' . $this->abbr_word_re . ')' .
3512
+				'(?![\w\x1A])' .
3513
+				'}',
3514
+				array(&$this, '_doAbbreviations_callback'),
3515
+				$text
3516
+			);
3517
+		}
3518
+		return $text;
3519
+	}
3520
+
3521
+	function _doAbbreviations_callback($matches)
3522
+	{
3523
+		$abbr = $matches[0];
3524
+		if (isset($this->abbr_desciptions[$abbr])) {
3525
+			$desc = $this->abbr_desciptions[$abbr];
3526
+			if (empty($desc)) {
3527
+				return $this->hashPart("<abbr>$abbr</abbr>");
3528
+			} else {
3529
+				$desc = $this->encodeAttribute($desc);
3530
+				return $this->hashPart("<abbr title=\"$desc\">$abbr</abbr>");
3531
+			}
3532
+		} else {
3533
+			return $matches[0];
3534
+		}
3535
+	}
3536 3536
 }
3537 3537
 
3538 3538
 /*
Please login to merge, or discard this patch.
myth/Models/CIDbModel.php 2 patches
Indentation   +1449 added lines, -1449 removed lines patch added patch discarded remove patch
@@ -1,34 +1,34 @@  discard block
 block discarded – undo
1 1
 <?php namespace Myth\Models;
2 2
 /**
3
- * Sprint
4
- *
5
- * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- *
25
- * @package     Sprint
26
- * @author      Lonnie Ezell
27
- * @copyright   Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
28
- * @license     http://opensource.org/licenses/MIT  (MIT)
29
- * @link        http://sprintphp.com
30
- * @since       Version 1.0
31
- */
3
+	 * Sprint
4
+	 *
5
+	 * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
6
+	 *
7
+	 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+	 * of this software and associated documentation files (the "Software"), to deal
9
+	 * in the Software without restriction, including without limitation the rights
10
+	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+	 * copies of the Software, and to permit persons to whom the Software is
12
+	 * furnished to do so, subject to the following conditions:
13
+	 *
14
+	 * The above copyright notice and this permission notice shall be included in
15
+	 * all copies or substantial portions of the Software.
16
+	 *
17
+	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+	 * THE SOFTWARE.
24
+	 *
25
+	 * @package     Sprint
26
+	 * @author      Lonnie Ezell
27
+	 * @copyright   Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
28
+	 * @license     http://opensource.org/licenses/MIT  (MIT)
29
+	 * @link        http://sprintphp.com
30
+	 * @since       Version 1.0
31
+	 */
32 32
 
33 33
 //--------------------------------------------------------------------
34 34
 
@@ -102,1479 +102,1479 @@  discard block
 block discarded – undo
102 102
 class CIDbModel
103 103
 {
104 104
 
105
-    /**
106
-     * The model's default table name.
107
-     *
108
-     * @var string;
109
-     */
110
-    protected $table_name;
111
-
112
-    /**
113
-     * The model's default primary key.
114
-     *
115
-     * @var string
116
-     */
117
-    protected $primary_key = 'id';
118
-
119
-    /**
120
-     * The type of date/time field used for created_on and modified_on fields.
121
-     * Valid types are: 'int', 'datetime', 'date'
122
-     *
123
-     * @var string
124
-     * @access protected
125
-     */
126
-    protected $date_format = 'datetime';
127
-
128
-    /*
105
+	/**
106
+	 * The model's default table name.
107
+	 *
108
+	 * @var string;
109
+	 */
110
+	protected $table_name;
111
+
112
+	/**
113
+	 * The model's default primary key.
114
+	 *
115
+	 * @var string
116
+	 */
117
+	protected $primary_key = 'id';
118
+
119
+	/**
120
+	 * The type of date/time field used for created_on and modified_on fields.
121
+	 * Valid types are: 'int', 'datetime', 'date'
122
+	 *
123
+	 * @var string
124
+	 * @access protected
125
+	 */
126
+	protected $date_format = 'datetime';
127
+
128
+	/*
129 129
         Var: $log_user
130 130
         If TRUE, will log user id for 'created_by', 'modified_by' and 'deleted_by'.
131 131
 
132 132
         Access:
133 133
             Protected
134 134
     */
135
-    protected $log_user = FALSE;
135
+	protected $log_user = FALSE;
136 136
 
137 137
 
138 138
 
139
-    /**
140
-     * Whether or not to auto-fill a 'created_on' field on inserts.
141
-     *
142
-     * @var boolean
143
-     * @access protected
144
-     */
145
-    protected $set_created = TRUE;
139
+	/**
140
+	 * Whether or not to auto-fill a 'created_on' field on inserts.
141
+	 *
142
+	 * @var boolean
143
+	 * @access protected
144
+	 */
145
+	protected $set_created = TRUE;
146 146
 
147
-    /**
148
-     * Field name to use to the created time column in the DB table.
149
-     *
150
-     * @var string
151
-     * @access protected
152
-     */
153
-    protected $created_field = 'created_on';
147
+	/**
148
+	 * Field name to use to the created time column in the DB table.
149
+	 *
150
+	 * @var string
151
+	 * @access protected
152
+	 */
153
+	protected $created_field = 'created_on';
154 154
 
155
-    /*
155
+	/*
156 156
         Var: $created_by_field
157 157
         Field name to use to the created by column in the DB table.
158 158
 
159 159
         Access:
160 160
             Protected
161 161
     */
162
-    protected $created_by_field = 'created_by';
162
+	protected $created_by_field = 'created_by';
163 163
 
164 164
 
165 165
 
166
-    /**
167
-     * Whether or not to auto-fill a 'modified_on' field on updates.
168
-     *
169
-     * @var boolean
170
-     * @access protected
171
-     */
172
-    protected $set_modified = TRUE;
166
+	/**
167
+	 * Whether or not to auto-fill a 'modified_on' field on updates.
168
+	 *
169
+	 * @var boolean
170
+	 * @access protected
171
+	 */
172
+	protected $set_modified = TRUE;
173 173
 
174
-    /**
175
-     * Field name to use to the modified time column in the DB table.
176
-     *
177
-     * @var string
178
-     * @access protected
179
-     */
180
-    protected $modified_field = 'modified_on';
174
+	/**
175
+	 * Field name to use to the modified time column in the DB table.
176
+	 *
177
+	 * @var string
178
+	 * @access protected
179
+	 */
180
+	protected $modified_field = 'modified_on';
181 181
 
182
-    /*
182
+	/*
183 183
         Var: $modified_by_field
184 184
         Field name to use to the modified by column in the DB table.
185 185
 
186 186
         Access:
187 187
             Protected
188 188
     */
189
-    protected $modified_by_field = 'modified_by';
189
+	protected $modified_by_field = 'modified_by';
190 190
 
191 191
 
192
-    /**
193
-     * Support for soft_deletes.
194
-     */
195
-    protected $soft_deletes = FALSE;
196
-    protected $soft_delete_key = 'deleted';
197
-    protected $temp_with_deleted = FALSE;
192
+	/**
193
+	 * Support for soft_deletes.
194
+	 */
195
+	protected $soft_deletes = FALSE;
196
+	protected $soft_delete_key = 'deleted';
197
+	protected $temp_with_deleted = FALSE;
198 198
 
199
-    /*
199
+	/*
200 200
         Var: $deleted_by_field
201 201
         Field name to use for the deleted by column in the DB table.
202 202
 
203 203
         Access:
204 204
             Protected
205 205
     */
206
-    protected $deleted_by_field = 'deleted_by';
206
+	protected $deleted_by_field = 'deleted_by';
207 207
 
208 208
 
209 209
 
210
-    /**
211
-     * Various callbacks available to the class. They are simple lists of
212
-     * method names (methods will be ran on $this).
213
-     */
214
-    protected $before_insert = array();
215
-    protected $after_insert = array();
216
-    protected $before_update = array();
217
-    protected $after_update = array();
218
-    protected $before_find = array();
219
-    protected $after_find = array();
220
-    protected $before_delete = array();
221
-    protected $after_delete = array();
210
+	/**
211
+	 * Various callbacks available to the class. They are simple lists of
212
+	 * method names (methods will be ran on $this).
213
+	 */
214
+	protected $before_insert = array();
215
+	protected $after_insert = array();
216
+	protected $before_update = array();
217
+	protected $after_update = array();
218
+	protected $before_find = array();
219
+	protected $after_find = array();
220
+	protected $before_delete = array();
221
+	protected $after_delete = array();
222 222
 
223
-    protected $callback_parameters = array();
223
+	protected $callback_parameters = array();
224 224
 
225 225
 
226 226
 
227
-    /*
227
+	/*
228 228
         If TRUE, inserts will return the last_insert_id. However,
229 229
         this can potentially slow down large imports drastically
230 230
         so you can turn it off with the return_insert_id(false) method.
231 231
      */
232
-    protected $return_insert_id = true;
233
-
234
-    /**
235
-     * By default, we return items as objects. You can change this for the
236
-     * entire class by setting this value to 'array' instead of 'object'.
237
-     * Alternatively, you can do it on a per-instance basis using the
238
-     * 'as_array()' and 'as_object()' methods.
239
-     */
240
-    protected $return_type = 'object';
241
-    protected $temp_return_type = NULL;
242
-
243
-    /**
244
-     * Protected, non-modifiable attributes
245
-     */
246
-    protected $protected_attributes = array();
247
-
248
-
249
-
250
-    /**
251
-     * An array of validation rules. This needs to be the same format
252
-     * as validation rules passed to the Form_validation library.
253
-     */
254
-    protected $validation_rules = array();
255
-
256
-    /**
257
-     * Optionally skip the validation. Used in conjunction with
258
-     * skip_validation() to skip data validation for any future calls.
259
-     */
260
-    protected $skip_validation = FALSE;
261
-
262
-    /**
263
-     * An array of extra rules to add to validation rules during inserts only.
264
-     * Often used for adding 'required' rules to fields on insert, but not udpates.
265
-     *
266
-     *   array( 'username' => 'required|strip_tags' );
267
-     * @var array
268
-     */
269
-    protected $insert_validate_rules = array();
270
-
271
-
272
-
273
-    /**
274
-     * @var Array Columns for the model's database fields
275
-     *
276
-     * This can be set to avoid a database call if using $this->prep_data()
277
-     */
278
-    protected $fields = array();
279
-
280
-    //--------------------------------------------------------------------
281
-
282
-    /**
283
-     * Does basic setup. Can pass the database connection into the constructor
284
-     * to use that $db instead of the global CI one.
285
-     *
286
-     * @param object $db // A database/driver instance
287
-     * @param object $form_validation // A form_validation library instance
288
-     */
289
-    public function __construct($db = null, $form_validation = null)
290
-    {
291
-        // Always protect our attributes
292
-        array_unshift($this->before_insert, 'protect_attributes');
293
-        array_unshift($this->before_update, 'protect_attributes');
294
-
295
-        // Check our auto-set features and make sure they are part of
296
-        // our observer system.
297
-        if ($this->set_created === true) array_unshift($this->before_insert, 'created_on');
298
-        if ($this->set_modified === true) array_unshift($this->before_update, 'modified_on');
299
-
300
-        // Make sure our temp return type is correct.
301
-        $this->temp_return_type = $this->return_type;
302
-
303
-        // Make sure our database is loaded
304
-        if (!is_null($db)) {
305
-            $this->db = $db;
306
-        }
307
-        else {
308
-            // Auto Init the damn database....
309
-            $this->load->database();
310
-        }
311
-
312
-        // Do we have a form_validation library?
313
-        if (! is_null($form_validation)) {
314
-            $this->form_validation = $form_validation;
315
-        }
316
-        else {
317
-            $this->load->library('form_validation');
318
-        }
232
+	protected $return_insert_id = true;
233
+
234
+	/**
235
+	 * By default, we return items as objects. You can change this for the
236
+	 * entire class by setting this value to 'array' instead of 'object'.
237
+	 * Alternatively, you can do it on a per-instance basis using the
238
+	 * 'as_array()' and 'as_object()' methods.
239
+	 */
240
+	protected $return_type = 'object';
241
+	protected $temp_return_type = NULL;
242
+
243
+	/**
244
+	 * Protected, non-modifiable attributes
245
+	 */
246
+	protected $protected_attributes = array();
247
+
248
+
249
+
250
+	/**
251
+	 * An array of validation rules. This needs to be the same format
252
+	 * as validation rules passed to the Form_validation library.
253
+	 */
254
+	protected $validation_rules = array();
255
+
256
+	/**
257
+	 * Optionally skip the validation. Used in conjunction with
258
+	 * skip_validation() to skip data validation for any future calls.
259
+	 */
260
+	protected $skip_validation = FALSE;
261
+
262
+	/**
263
+	 * An array of extra rules to add to validation rules during inserts only.
264
+	 * Often used for adding 'required' rules to fields on insert, but not udpates.
265
+	 *
266
+	 *   array( 'username' => 'required|strip_tags' );
267
+	 * @var array
268
+	 */
269
+	protected $insert_validate_rules = array();
270
+
271
+
272
+
273
+	/**
274
+	 * @var Array Columns for the model's database fields
275
+	 *
276
+	 * This can be set to avoid a database call if using $this->prep_data()
277
+	 */
278
+	protected $fields = array();
279
+
280
+	//--------------------------------------------------------------------
281
+
282
+	/**
283
+	 * Does basic setup. Can pass the database connection into the constructor
284
+	 * to use that $db instead of the global CI one.
285
+	 *
286
+	 * @param object $db // A database/driver instance
287
+	 * @param object $form_validation // A form_validation library instance
288
+	 */
289
+	public function __construct($db = null, $form_validation = null)
290
+	{
291
+		// Always protect our attributes
292
+		array_unshift($this->before_insert, 'protect_attributes');
293
+		array_unshift($this->before_update, 'protect_attributes');
294
+
295
+		// Check our auto-set features and make sure they are part of
296
+		// our observer system.
297
+		if ($this->set_created === true) array_unshift($this->before_insert, 'created_on');
298
+		if ($this->set_modified === true) array_unshift($this->before_update, 'modified_on');
299
+
300
+		// Make sure our temp return type is correct.
301
+		$this->temp_return_type = $this->return_type;
302
+
303
+		// Make sure our database is loaded
304
+		if (!is_null($db)) {
305
+			$this->db = $db;
306
+		}
307
+		else {
308
+			// Auto Init the damn database....
309
+			$this->load->database();
310
+		}
311
+
312
+		// Do we have a form_validation library?
313
+		if (! is_null($form_validation)) {
314
+			$this->form_validation = $form_validation;
315
+		}
316
+		else {
317
+			$this->load->library('form_validation');
318
+		}
319 319
         
320
-        log_message('debug', 'CIDbModel Class Initialized');
321
-    }
322
-
323
-    //--------------------------------------------------------------------
324
-
325
-    //--------------------------------------------------------------------
326
-    // CRUD Methods
327
-    //--------------------------------------------------------------------
328
-
329
-    /**
330
-     * A simple way to grab the first result of a search only.
331
-     */
332
-    public function first()
333
-    {
334
-        $rows = $this->limit(1, 0)->find_all();
335
-
336
-        if (is_array($rows) && count($rows)) {
337
-            return $rows[0];
338
-        }
339
-
340
-        return $rows;
341
-    }
342
-
343
-    //--------------------------------------------------------------------
344
-
345
-
346
-    /**
347
-     * Finds a single record based on it's primary key. Will ignore deleted rows.
348
-     *
349
-     * @param  mixed $id The primary_key value of the object to retrieve.
350
-     * @return object
351
-     */
352
-    public function find($id)
353
-    {
354
-        $this->trigger('before_find', ['id' => $id, 'method' => 'find']);
355
-
356
-        // Ignore any soft-deleted rows
357
-        if ($this->soft_deletes) {
358
-            // We only need to modify the where statement if
359
-            // temp_with_deleted is false.
360
-            if ($this->temp_with_deleted !== true) {
361
-                $this->db->where($this->soft_delete_key, false);
362
-            }
363
-
364
-            $this->temp_with_deleted = false;
365
-        }
366
-
367
-        $this->db->where($this->primary_key, $id);
368
-        $row = $this->db->get($this->table_name);
369
-        $row = $this->temp_return_type == 'array' ? $row->row_array() : $row->row(0, $this->temp_return_type);
370
-
371
-        if ( ! empty($row))
372
-        {
373
-            $row = $this->trigger('after_find', ['id' => $id, 'method' => 'find', 'fields' => $row]);
374
-        }
375
-
376
-        // Reset our return type
377
-        $this->temp_return_type = $this->return_type;
378
-
379
-        return $row;
380
-    }
381
-
382
-    //--------------------------------------------------------------------
383
-
384
-    /**
385
-     * Fetch a single record based on an arbitrary WHERE call. Can be
386
-     * any valid value to $this->db->where(). Will not pull in deleted rows
387
-     * if using soft deletes.
388
-     *
389
-     * @return object
390
-     */
391
-    public function find_by()
392
-    {
393
-        $where = func_get_args();
394
-        $this->_set_where($where);
395
-
396
-        // Ignore any soft-deleted rows
397
-        if ($this->soft_deletes) {
398
-            // We only need to modify the where statement if
399
-            // temp_with_deleted is false.
400
-            if ($this->temp_with_deleted !== true) {
401
-                $this->db->where($this->soft_delete_key, false);
402
-            }
403
-
404
-            $this->temp_with_deleted = false;
405
-        }
406
-
407
-        $this->trigger('before_find', ['method' => 'find_by', 'fields' => $where]);
408
-
409
-        $row = $this->db->get($this->table_name);
410
-        $row = $this->temp_return_type == 'array' ? $row->row_array() : $row->row(0, $this->temp_return_type);
411
-
412
-        if ( ! empty($row))
413
-        {
414
-            $row = $this->trigger('after_find', ['method' => 'find_by', 'fields' => $row]);
415
-        }
416
-
417
-        // Reset our return type
418
-        $this->temp_return_type = $this->return_type;
419
-
420
-        return $row;
421
-    }
422
-
423
-    //--------------------------------------------------------------------
424
-
425
-    /**
426
-     * Retrieves a number of items based on an array of primary_values passed in.
427
-     *
428
-     * @param  array $values An array of primary key values to find.
429
-     *
430
-     * @return object or FALSE
431
-     */
432
-    public function find_many($values)
433
-    {
434
-        $this->db->where_in($this->primary_key, $values);
435
-
436
-        return $this->find_all();
437
-    }
438
-
439
-    //--------------------------------------------------------------------
440
-
441
-    /**
442
-     * Retrieves a number of items based on an arbitrary WHERE call. Can be
443
-     * any set of parameters valid to $db->where.
444
-     *
445
-     * @return object or FALSE
446
-     */
447
-    public function find_many_by()
448
-    {
449
-        $where = func_get_args();
450
-        $this->_set_where($where);
451
-
452
-        return $this->find_all();
453
-    }
454
-
455
-    //--------------------------------------------------------------------
456
-
457
-    /**
458
-     * Fetch all of the records in the table. Can be used with scoped calls
459
-     * to restrict the results.
460
-     *
461
-     * @return object or FALSE
462
-     */
463
-    public function find_all()
464
-    {
465
-        $this->trigger('before_find', ['method' => 'find_all']);
466
-
467
-        // Ignore any soft-deleted rows
468
-        if ($this->soft_deletes) {
469
-            // We only need to modify the where statement if
470
-            // temp_with_deleted is false.
471
-            if ($this->temp_with_deleted !== true) {
472
-                $this->db->where($this->soft_delete_key, false);
473
-            }
474
-
475
-            $this->temp_with_deleted = false;
476
-        }
477
-
478
-        $rows = $this->db->get($this->table_name);
479
-        $rows = $this->temp_return_type == 'array' ? $rows->result_array() : $rows->result($this->temp_return_type);
480
-
481
-        if (is_array($rows)) {
482
-            foreach ($rows as $key => &$row) {
483
-                $row = $this->trigger('after_find', ['method' => 'find_all', 'fields' => $row] );
484
-            }
485
-        }
486
-
487
-        // Reset our return type
488
-        $this->temp_return_type = $this->return_type;
489
-
490
-        return $rows;
491
-    }
492
-
493
-    //--------------------------------------------------------------------
494
-
495
-    /**
496
-     * Inserts data into the database.
497
-     *
498
-     * @param  array $data An array of key/value pairs to insert to database.
499
-     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
500
-     * @return mixed       The primary_key value of the inserted record, or FALSE.
501
-     */
502
-    public function insert($data, $skip_validation = null)
503
-    {
504
-        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
505
-
506
-        if ($skip_validation === FALSE) {
507
-            $data = $this->validate($data, 'insert', $skip_validation);
508
-        }
509
-
510
-        if ($data !== FALSE) {
511
-            $data = $this->trigger('before_insert', ['method' => 'insert', 'fields' => $data]);
512
-
513
-            $this->db->insert($this->table_name, $this->prep_data($data) );
514
-
515
-            if ($this->return_insert_id) {
516
-                $id = $this->db->insert_id();
517
-
518
-                $this->trigger('after_insert', ['id' => $id, 'fields' => $data, 'method' => 'insert']);
519
-
520
-                return $id;
521
-            }
522
-
523
-            return TRUE;
524
-        } else {
525
-            return FALSE;
526
-        }
527
-    }
528
-
529
-    //--------------------------------------------------------------------
530
-
531
-    /**
532
-     * Inserts multiple rows into the database at once. Takes an associative
533
-     * array of value pairs.
534
-     *
535
-     * $data = array(
536
-     *     array(
537
-     *         'title' => 'My title'
538
-     *     ),
539
-     *     array(
540
-     *         'title'  => 'My Other Title'
541
-     *     )
542
-     * );
543
-     *
544
-     * @param  array $data An associate array of rows to insert
545
-     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
546
-     * @return bool
547
-     */
548
-    public function insert_batch($data, $skip_validation = null)
549
-    {
550
-        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
551
-
552
-        if ($skip_validation === FALSE) {
553
-            $data = $this->validate($data, 'insert', $skip_validation);
554
-        }
555
-
556
-        if ($data !== FALSE) {
557
-            $data['batch'] = true;
558
-            $data = $this->trigger('before_insert', ['method' => 'insert_batch', 'fields' => $data] );
559
-            unset($data['batch']);
560
-
561
-            return $this->db->insert_batch($this->table_name, $data);
562
-        } else {
563
-            return FALSE;
564
-        }
565
-    }
566
-
567
-    //--------------------------------------------------------------------
568
-
569
-    /**
570
-     * Performs the SQL standard for a combined DELETE + INSERT, using
571
-     * PRIMARY and UNIQUE keys to determine which row to replace.
572
-     *
573
-     * See CI's documentation for the replace method. We simply wrap
574
-     * our validation and triggers around their method.
575
-     *
576
-     * @param $data
577
-     * @param null $skip_validation
578
-     * @return bool
579
-     */
580
-    public function replace($data, $skip_validation=null)
581
-    {
582
-        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
583
-
584
-        if ($skip_validation === FALSE) {
585
-            $data = $this->validate($data, 'insert', $skip_validation);
586
-        }
587
-
588
-        if ($data !== FALSE) {
589
-            $this->db->replace($this->table_name, $this->prep_data($data));
590
-
591
-            if ($this->return_insert_id) {
592
-                $id = $this->db->insert_id();
593
-
594
-                $this->trigger('after_insert', ['id' => $id, 'fields' => $data, 'method'=>'replace']);
595
-
596
-                return $id;
597
-            }
598
-
599
-            return TRUE;
600
-        } else {
601
-            return FALSE;
602
-        }
603
-    }
604
-
605
-    //--------------------------------------------------------------------
606
-
607
-
608
-    /**
609
-     * Updates an existing record in the database.
610
-     *
611
-     * @param  mixed $id The primary_key value of the record to update.
612
-     * @param  array $data An array of value pairs to update in the record.
613
-     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
614
-     * @return bool
615
-     */
616
-    public function update($id, $data, $skip_validation = null)
617
-    {
618
-        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
619
-
620
-        if ($skip_validation === FALSE) {
621
-            $data = $this->validate($data);
622
-        }
623
-
624
-        // Will be false if it didn't validate.
625
-        if ($data !== FALSE) {
320
+		log_message('debug', 'CIDbModel Class Initialized');
321
+	}
322
+
323
+	//--------------------------------------------------------------------
324
+
325
+	//--------------------------------------------------------------------
326
+	// CRUD Methods
327
+	//--------------------------------------------------------------------
328
+
329
+	/**
330
+	 * A simple way to grab the first result of a search only.
331
+	 */
332
+	public function first()
333
+	{
334
+		$rows = $this->limit(1, 0)->find_all();
335
+
336
+		if (is_array($rows) && count($rows)) {
337
+			return $rows[0];
338
+		}
339
+
340
+		return $rows;
341
+	}
342
+
343
+	//--------------------------------------------------------------------
344
+
345
+
346
+	/**
347
+	 * Finds a single record based on it's primary key. Will ignore deleted rows.
348
+	 *
349
+	 * @param  mixed $id The primary_key value of the object to retrieve.
350
+	 * @return object
351
+	 */
352
+	public function find($id)
353
+	{
354
+		$this->trigger('before_find', ['id' => $id, 'method' => 'find']);
355
+
356
+		// Ignore any soft-deleted rows
357
+		if ($this->soft_deletes) {
358
+			// We only need to modify the where statement if
359
+			// temp_with_deleted is false.
360
+			if ($this->temp_with_deleted !== true) {
361
+				$this->db->where($this->soft_delete_key, false);
362
+			}
363
+
364
+			$this->temp_with_deleted = false;
365
+		}
366
+
367
+		$this->db->where($this->primary_key, $id);
368
+		$row = $this->db->get($this->table_name);
369
+		$row = $this->temp_return_type == 'array' ? $row->row_array() : $row->row(0, $this->temp_return_type);
370
+
371
+		if ( ! empty($row))
372
+		{
373
+			$row = $this->trigger('after_find', ['id' => $id, 'method' => 'find', 'fields' => $row]);
374
+		}
375
+
376
+		// Reset our return type
377
+		$this->temp_return_type = $this->return_type;
378
+
379
+		return $row;
380
+	}
381
+
382
+	//--------------------------------------------------------------------
383
+
384
+	/**
385
+	 * Fetch a single record based on an arbitrary WHERE call. Can be
386
+	 * any valid value to $this->db->where(). Will not pull in deleted rows
387
+	 * if using soft deletes.
388
+	 *
389
+	 * @return object
390
+	 */
391
+	public function find_by()
392
+	{
393
+		$where = func_get_args();
394
+		$this->_set_where($where);
395
+
396
+		// Ignore any soft-deleted rows
397
+		if ($this->soft_deletes) {
398
+			// We only need to modify the where statement if
399
+			// temp_with_deleted is false.
400
+			if ($this->temp_with_deleted !== true) {
401
+				$this->db->where($this->soft_delete_key, false);
402
+			}
403
+
404
+			$this->temp_with_deleted = false;
405
+		}
406
+
407
+		$this->trigger('before_find', ['method' => 'find_by', 'fields' => $where]);
408
+
409
+		$row = $this->db->get($this->table_name);
410
+		$row = $this->temp_return_type == 'array' ? $row->row_array() : $row->row(0, $this->temp_return_type);
411
+
412
+		if ( ! empty($row))
413
+		{
414
+			$row = $this->trigger('after_find', ['method' => 'find_by', 'fields' => $row]);
415
+		}
416
+
417
+		// Reset our return type
418
+		$this->temp_return_type = $this->return_type;
419
+
420
+		return $row;
421
+	}
422
+
423
+	//--------------------------------------------------------------------
424
+
425
+	/**
426
+	 * Retrieves a number of items based on an array of primary_values passed in.
427
+	 *
428
+	 * @param  array $values An array of primary key values to find.
429
+	 *
430
+	 * @return object or FALSE
431
+	 */
432
+	public function find_many($values)
433
+	{
434
+		$this->db->where_in($this->primary_key, $values);
435
+
436
+		return $this->find_all();
437
+	}
438
+
439
+	//--------------------------------------------------------------------
440
+
441
+	/**
442
+	 * Retrieves a number of items based on an arbitrary WHERE call. Can be
443
+	 * any set of parameters valid to $db->where.
444
+	 *
445
+	 * @return object or FALSE
446
+	 */
447
+	public function find_many_by()
448
+	{
449
+		$where = func_get_args();
450
+		$this->_set_where($where);
451
+
452
+		return $this->find_all();
453
+	}
454
+
455
+	//--------------------------------------------------------------------
456
+
457
+	/**
458
+	 * Fetch all of the records in the table. Can be used with scoped calls
459
+	 * to restrict the results.
460
+	 *
461
+	 * @return object or FALSE
462
+	 */
463
+	public function find_all()
464
+	{
465
+		$this->trigger('before_find', ['method' => 'find_all']);
466
+
467
+		// Ignore any soft-deleted rows
468
+		if ($this->soft_deletes) {
469
+			// We only need to modify the where statement if
470
+			// temp_with_deleted is false.
471
+			if ($this->temp_with_deleted !== true) {
472
+				$this->db->where($this->soft_delete_key, false);
473
+			}
474
+
475
+			$this->temp_with_deleted = false;
476
+		}
477
+
478
+		$rows = $this->db->get($this->table_name);
479
+		$rows = $this->temp_return_type == 'array' ? $rows->result_array() : $rows->result($this->temp_return_type);
480
+
481
+		if (is_array($rows)) {
482
+			foreach ($rows as $key => &$row) {
483
+				$row = $this->trigger('after_find', ['method' => 'find_all', 'fields' => $row] );
484
+			}
485
+		}
486
+
487
+		// Reset our return type
488
+		$this->temp_return_type = $this->return_type;
489
+
490
+		return $rows;
491
+	}
492
+
493
+	//--------------------------------------------------------------------
494
+
495
+	/**
496
+	 * Inserts data into the database.
497
+	 *
498
+	 * @param  array $data An array of key/value pairs to insert to database.
499
+	 * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
500
+	 * @return mixed       The primary_key value of the inserted record, or FALSE.
501
+	 */
502
+	public function insert($data, $skip_validation = null)
503
+	{
504
+		$skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
505
+
506
+		if ($skip_validation === FALSE) {
507
+			$data = $this->validate($data, 'insert', $skip_validation);
508
+		}
509
+
510
+		if ($data !== FALSE) {
511
+			$data = $this->trigger('before_insert', ['method' => 'insert', 'fields' => $data]);
512
+
513
+			$this->db->insert($this->table_name, $this->prep_data($data) );
514
+
515
+			if ($this->return_insert_id) {
516
+				$id = $this->db->insert_id();
517
+
518
+				$this->trigger('after_insert', ['id' => $id, 'fields' => $data, 'method' => 'insert']);
519
+
520
+				return $id;
521
+			}
522
+
523
+			return TRUE;
524
+		} else {
525
+			return FALSE;
526
+		}
527
+	}
528
+
529
+	//--------------------------------------------------------------------
530
+
531
+	/**
532
+	 * Inserts multiple rows into the database at once. Takes an associative
533
+	 * array of value pairs.
534
+	 *
535
+	 * $data = array(
536
+	 *     array(
537
+	 *         'title' => 'My title'
538
+	 *     ),
539
+	 *     array(
540
+	 *         'title'  => 'My Other Title'
541
+	 *     )
542
+	 * );
543
+	 *
544
+	 * @param  array $data An associate array of rows to insert
545
+	 * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
546
+	 * @return bool
547
+	 */
548
+	public function insert_batch($data, $skip_validation = null)
549
+	{
550
+		$skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
551
+
552
+		if ($skip_validation === FALSE) {
553
+			$data = $this->validate($data, 'insert', $skip_validation);
554
+		}
555
+
556
+		if ($data !== FALSE) {
557
+			$data['batch'] = true;
558
+			$data = $this->trigger('before_insert', ['method' => 'insert_batch', 'fields' => $data] );
559
+			unset($data['batch']);
560
+
561
+			return $this->db->insert_batch($this->table_name, $data);
562
+		} else {
563
+			return FALSE;
564
+		}
565
+	}
566
+
567
+	//--------------------------------------------------------------------
568
+
569
+	/**
570
+	 * Performs the SQL standard for a combined DELETE + INSERT, using
571
+	 * PRIMARY and UNIQUE keys to determine which row to replace.
572
+	 *
573
+	 * See CI's documentation for the replace method. We simply wrap
574
+	 * our validation and triggers around their method.
575
+	 *
576
+	 * @param $data
577
+	 * @param null $skip_validation
578
+	 * @return bool
579
+	 */
580
+	public function replace($data, $skip_validation=null)
581
+	{
582
+		$skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
583
+
584
+		if ($skip_validation === FALSE) {
585
+			$data = $this->validate($data, 'insert', $skip_validation);
586
+		}
587
+
588
+		if ($data !== FALSE) {
589
+			$this->db->replace($this->table_name, $this->prep_data($data));
590
+
591
+			if ($this->return_insert_id) {
592
+				$id = $this->db->insert_id();
593
+
594
+				$this->trigger('after_insert', ['id' => $id, 'fields' => $data, 'method'=>'replace']);
595
+
596
+				return $id;
597
+			}
598
+
599
+			return TRUE;
600
+		} else {
601
+			return FALSE;
602
+		}
603
+	}
604
+
605
+	//--------------------------------------------------------------------
606
+
607
+
608
+	/**
609
+	 * Updates an existing record in the database.
610
+	 *
611
+	 * @param  mixed $id The primary_key value of the record to update.
612
+	 * @param  array $data An array of value pairs to update in the record.
613
+	 * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
614
+	 * @return bool
615
+	 */
616
+	public function update($id, $data, $skip_validation = null)
617
+	{
618
+		$skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
619
+
620
+		if ($skip_validation === FALSE) {
621
+			$data = $this->validate($data);
622
+		}
623
+
624
+		// Will be false if it didn't validate.
625
+		if ($data !== FALSE) {
626 626
             
627
-            $data = $this->trigger('before_update', ['id' => $id, 'method' =>'update', 'fields' => $data] );
627
+			$data = $this->trigger('before_update', ['id' => $id, 'method' =>'update', 'fields' => $data] );
628 628
             
629
-            $this->db->where($this->primary_key, $id);
630
-            $this->db->set( $this->prep_data($data) );
631
-            $result = $this->db->update($this->table_name);
632
-
633
-            $this->trigger('after_update', ['id' => $id, 'fields' => $data, 'result' => $result, 'method' => 'update']);
634
-
635
-            return $result;
636
-        } else {
637
-            return FALSE;
638
-        }
639
-    }
640
-
641
-    //--------------------------------------------------------------------
642
-
643
-    /**
644
-     * Updates multiple records in the database at once.
645
-     *
646
-     * $data = array(
647
-     *     array(
648
-     *         'title'  => 'My title',
649
-     *         'body'   => 'body 1'
650
-     *     ),
651
-     *     array(
652
-     *         'title'  => 'Another Title',
653
-     *         'body'   => 'body 2'
654
-     *     )
655
-     * );
656
-     *
657
-     * The $where_key should be the name of the column to match the record on.
658
-     * If $where_key == 'title', then each record would be matched on that
659
-     * 'title' value of the array. This does mean that the array key needs
660
-     * to be provided with each row's data.
661
-     *
662
-     * @param  array $data An associate array of row data to update.
663
-     * @param  string $where_key The column name to match on.
664
-     * @return bool
665
-     */
666
-    public function update_batch($data, $where_key)
667
-    {
668
-        foreach ($data as &$row) {
669
-            $row = $this->trigger('before_update', ['method' => 'update_batch', 'fields' => $row] );
670
-        }
671
-
672
-        $result = $this->db->update_batch($this->table_name, $data, $where_key);
673
-
674
-        foreach ($data as &$row) {
675
-            $this->trigger('after_update', ['fields' => $data, 'result' => $result, 'method' => 'update_batch']);
676
-        }
677
-
678
-        return $result;
679
-    }
680
-
681
-    //--------------------------------------------------------------------
682
-
683
-    /**
684
-     * Updates many records by an array of ids.
685
-     *
686
-     * While update_batch() allows modifying multiple, arbitrary rows of data
687
-     * on each row, update_many() sets the same values for each row.
688
-     *
689
-     * $ids = array(1, 2, 3, 5, 12);
690
-     * $data = array(
691
-     *     'deleted_by' => 1
692
-     * );
693
-     *
694
-     * $this->model->update_many($ids, $data);
695
-     *
696
-     * @param  array $ids An array of primary_key values to update.
697
-     * @param  array $data An array of value pairs to modify in each row.
698
-     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
699
-     * @return bool
700
-     */
701
-    public function update_many($ids, $data, $skip_validation = null)
702
-    {
703
-        if (!is_array($ids) || count($ids) == 0) return NULL;
704
-
705
-        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
706
-
707
-        if ($skip_validation === FALSE) {
708
-            $data = $this->validate($data, 'update', $skip_validation);
709
-        }
710
-
711
-        $data = $this->trigger('before_update', ['ids' => $ids, 'method' => 'update_many', 'fields' => $data]);
712
-
713
-        // Will be false if it didn't validate.
714
-        if ($data !== FALSE) {
715
-            $this->db->where_in($this->primary_key, $ids);
716
-            $this->db->set($data);
717
-            $result = $this->db->update($this->table_name);
718
-
719
-            $this->trigger('after_update', ['ids' => $ids, 'fields' => $data, 'result'=>$result, 'method' => 'update_many']);
720
-
721
-            return $result;
722
-        } else {
723
-            return FALSE;
724
-        }
725
-    }
726
-
727
-    //--------------------------------------------------------------------
728
-
729
-    /**
730
-     * Update records in the database using a standard WHERE clause.
731
-     *
732
-     * Your last parameter should be the $data array with values to update
733
-     * on the rows. Any additional parameters should be provided to make up
734
-     * a typical WHERE clause. This could be a single array, or a column name
735
-     * and a value.
736
-     *
737
-     * $data = array('deleted_by' => 1);
738
-     * $wheres = array('user_id' => 15);
739
-     *
740
-     * $this->update_by($wheres, $data);
741
-     * $this->update_by('user_id', 15, $data);
742
-     *
743
-     * @param array $data An array of data pairs to update
744
-     * @param one or more WHERE-acceptable entries.
745
-     * @return bool
746
-     */
747
-    public function update_by()
748
-    {
749
-        $args = func_get_args();
750
-        $data = array_pop($args);
751
-        $this->_set_where($args);
752
-
753
-        $data = $this->trigger('before_update', ['method' => 'update_by', 'fields' => $data]);
754
-
755
-        // Will be false if it didn't validate.
756
-        if ($this->validate($data) !== FALSE) {
757
-            $this->db->set( $this->prep_data($data) );
758
-            $result = $this->db->update($this->table_name);
759
-
760
-            $this->trigger('after_update', ['method' => 'update_by', 'fields' => $data, 'result' => $result] );
761
-
762
-            return $result;
763
-        } else {
764
-            return FALSE;
765
-        }
766
-    }
767
-
768
-    //--------------------------------------------------------------------
769
-
770
-    /**
771
-     * Updates all records and sets the value pairs passed in the array.
772
-     *
773
-     * @param  array $data An array of value pairs with the data to change.
774
-     * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
775
-     * @return bool
776
-     */
777
-    public function update_all($data, $skip_validation = FALSE)
778
-    {
779
-        $data = $this->trigger('before_update', ['method' => 'update_all', 'fields' => $data] );
780
-
781
-        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
782
-
783
-        if ($skip_validation === FALSE) {
784
-            $data = $this->validate($data);
785
-        }
786
-
787
-        // Will be false if it didn't validate.
788
-        if ($data !== FALSE) {
789
-            $this->db->set( $this->prep_data($data) );
790
-            $result = $this->db->update($this->table_name);
791
-
792
-            $this->trigger('after_update', ['method' => 'update_all', 'fields' => $data, 'result' => $result] );
793
-
794
-            return $result;
795
-        } else {
796
-            return FALSE;
797
-        }
798
-    }
799
-
800
-    //--------------------------------------------------------------------
801
-
802
-    /**
803
-     * Increments the value of field for a given row, selected by the
804
-     * primary key for the table.
805
-     *
806
-     * @param $id
807
-     * @param $field
808
-     * @param int $value
809
-     * @return mixed
810
-     */
811
-    public function increment($id, $field, $value=1)
812
-    {
813
-        $value = (int)abs($value);
814
-
815
-        $this->db->where($this->primary_key, $id);
816
-        $this->db->set($field, "{$field}+{$value}", false);
817
-
818
-        return $this->db->update($this->table_name);
819
-    }
820
-
821
-    //--------------------------------------------------------------------
822
-
823
-    /**
824
-     * Increments the value of field for a given row, selected by the
825
-     * primary key for the table.
826
-     *
827
-     * @param $id
828
-     * @param $field
829
-     * @param int $value
830
-     * @return mixed
831
-     */
832
-    public function decrement($id, $field, $value=1)
833
-    {
834
-        $value = (int)abs($value);
835
-
836
-        $this->db->where($this->primary_key, $id);
837
-        $this->db->set($field, "{$field}-{$value}", false);
838
-
839
-        return $this->db->update($this->table_name);
840
-    }
841
-
842
-    //--------------------------------------------------------------------
843
-
844
-    /**
845
-     * Deletes a row by it's primary key value.
846
-     *
847
-     * @param  mixed $id The primary key value of the row to delete.
848
-     * @return bool
849
-     */
850
-    public function delete($id)
851
-    {
852
-        $this->trigger('before_delete', ['id' => $id, 'method' => 'delete'] );
853
-
854
-        $this->db->where($this->primary_key, $id);
629
+			$this->db->where($this->primary_key, $id);
630
+			$this->db->set( $this->prep_data($data) );
631
+			$result = $this->db->update($this->table_name);
632
+
633
+			$this->trigger('after_update', ['id' => $id, 'fields' => $data, 'result' => $result, 'method' => 'update']);
634
+
635
+			return $result;
636
+		} else {
637
+			return FALSE;
638
+		}
639
+	}
640
+
641
+	//--------------------------------------------------------------------
642
+
643
+	/**
644
+	 * Updates multiple records in the database at once.
645
+	 *
646
+	 * $data = array(
647
+	 *     array(
648
+	 *         'title'  => 'My title',
649
+	 *         'body'   => 'body 1'
650
+	 *     ),
651
+	 *     array(
652
+	 *         'title'  => 'Another Title',
653
+	 *         'body'   => 'body 2'
654
+	 *     )
655
+	 * );
656
+	 *
657
+	 * The $where_key should be the name of the column to match the record on.
658
+	 * If $where_key == 'title', then each record would be matched on that
659
+	 * 'title' value of the array. This does mean that the array key needs
660
+	 * to be provided with each row's data.
661
+	 *
662
+	 * @param  array $data An associate array of row data to update.
663
+	 * @param  string $where_key The column name to match on.
664
+	 * @return bool
665
+	 */
666
+	public function update_batch($data, $where_key)
667
+	{
668
+		foreach ($data as &$row) {
669
+			$row = $this->trigger('before_update', ['method' => 'update_batch', 'fields' => $row] );
670
+		}
671
+
672
+		$result = $this->db->update_batch($this->table_name, $data, $where_key);
673
+
674
+		foreach ($data as &$row) {
675
+			$this->trigger('after_update', ['fields' => $data, 'result' => $result, 'method' => 'update_batch']);
676
+		}
677
+
678
+		return $result;
679
+	}
680
+
681
+	//--------------------------------------------------------------------
682
+
683
+	/**
684
+	 * Updates many records by an array of ids.
685
+	 *
686
+	 * While update_batch() allows modifying multiple, arbitrary rows of data
687
+	 * on each row, update_many() sets the same values for each row.
688
+	 *
689
+	 * $ids = array(1, 2, 3, 5, 12);
690
+	 * $data = array(
691
+	 *     'deleted_by' => 1
692
+	 * );
693
+	 *
694
+	 * $this->model->update_many($ids, $data);
695
+	 *
696
+	 * @param  array $ids An array of primary_key values to update.
697
+	 * @param  array $data An array of value pairs to modify in each row.
698
+	 * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
699
+	 * @return bool
700
+	 */
701
+	public function update_many($ids, $data, $skip_validation = null)
702
+	{
703
+		if (!is_array($ids) || count($ids) == 0) return NULL;
704
+
705
+		$skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
706
+
707
+		if ($skip_validation === FALSE) {
708
+			$data = $this->validate($data, 'update', $skip_validation);
709
+		}
710
+
711
+		$data = $this->trigger('before_update', ['ids' => $ids, 'method' => 'update_many', 'fields' => $data]);
712
+
713
+		// Will be false if it didn't validate.
714
+		if ($data !== FALSE) {
715
+			$this->db->where_in($this->primary_key, $ids);
716
+			$this->db->set($data);
717
+			$result = $this->db->update($this->table_name);
718
+
719
+			$this->trigger('after_update', ['ids' => $ids, 'fields' => $data, 'result'=>$result, 'method' => 'update_many']);
720
+
721
+			return $result;
722
+		} else {
723
+			return FALSE;
724
+		}
725
+	}
726
+
727
+	//--------------------------------------------------------------------
728
+
729
+	/**
730
+	 * Update records in the database using a standard WHERE clause.
731
+	 *
732
+	 * Your last parameter should be the $data array with values to update
733
+	 * on the rows. Any additional parameters should be provided to make up
734
+	 * a typical WHERE clause. This could be a single array, or a column name
735
+	 * and a value.
736
+	 *
737
+	 * $data = array('deleted_by' => 1);
738
+	 * $wheres = array('user_id' => 15);
739
+	 *
740
+	 * $this->update_by($wheres, $data);
741
+	 * $this->update_by('user_id', 15, $data);
742
+	 *
743
+	 * @param array $data An array of data pairs to update
744
+	 * @param one or more WHERE-acceptable entries.
745
+	 * @return bool
746
+	 */
747
+	public function update_by()
748
+	{
749
+		$args = func_get_args();
750
+		$data = array_pop($args);
751
+		$this->_set_where($args);
752
+
753
+		$data = $this->trigger('before_update', ['method' => 'update_by', 'fields' => $data]);
754
+
755
+		// Will be false if it didn't validate.
756
+		if ($this->validate($data) !== FALSE) {
757
+			$this->db->set( $this->prep_data($data) );
758
+			$result = $this->db->update($this->table_name);
759
+
760
+			$this->trigger('after_update', ['method' => 'update_by', 'fields' => $data, 'result' => $result] );
761
+
762
+			return $result;
763
+		} else {
764
+			return FALSE;
765
+		}
766
+	}
767
+
768
+	//--------------------------------------------------------------------
769
+
770
+	/**
771
+	 * Updates all records and sets the value pairs passed in the array.
772
+	 *
773
+	 * @param  array $data An array of value pairs with the data to change.
774
+	 * @param  array $skip_validation If TRUE, will skip validation of data for this call only.
775
+	 * @return bool
776
+	 */
777
+	public function update_all($data, $skip_validation = FALSE)
778
+	{
779
+		$data = $this->trigger('before_update', ['method' => 'update_all', 'fields' => $data] );
780
+
781
+		$skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
782
+
783
+		if ($skip_validation === FALSE) {
784
+			$data = $this->validate($data);
785
+		}
786
+
787
+		// Will be false if it didn't validate.
788
+		if ($data !== FALSE) {
789
+			$this->db->set( $this->prep_data($data) );
790
+			$result = $this->db->update($this->table_name);
791
+
792
+			$this->trigger('after_update', ['method' => 'update_all', 'fields' => $data, 'result' => $result] );
793
+
794
+			return $result;
795
+		} else {
796
+			return FALSE;
797
+		}
798
+	}
799
+
800
+	//--------------------------------------------------------------------
801
+
802
+	/**
803
+	 * Increments the value of field for a given row, selected by the
804
+	 * primary key for the table.
805
+	 *
806
+	 * @param $id
807
+	 * @param $field
808
+	 * @param int $value
809
+	 * @return mixed
810
+	 */
811
+	public function increment($id, $field, $value=1)
812
+	{
813
+		$value = (int)abs($value);
814
+
815
+		$this->db->where($this->primary_key, $id);
816
+		$this->db->set($field, "{$field}+{$value}", false);
817
+
818
+		return $this->db->update($this->table_name);
819
+	}
820
+
821
+	//--------------------------------------------------------------------
822
+
823
+	/**
824
+	 * Increments the value of field for a given row, selected by the
825
+	 * primary key for the table.
826
+	 *
827
+	 * @param $id
828
+	 * @param $field
829
+	 * @param int $value
830
+	 * @return mixed
831
+	 */
832
+	public function decrement($id, $field, $value=1)
833
+	{
834
+		$value = (int)abs($value);
835
+
836
+		$this->db->where($this->primary_key, $id);
837
+		$this->db->set($field, "{$field}-{$value}", false);
838
+
839
+		return $this->db->update($this->table_name);
840
+	}
841
+
842
+	//--------------------------------------------------------------------
843
+
844
+	/**
845
+	 * Deletes a row by it's primary key value.
846
+	 *
847
+	 * @param  mixed $id The primary key value of the row to delete.
848
+	 * @return bool
849
+	 */
850
+	public function delete($id)
851
+	{
852
+		$this->trigger('before_delete', ['id' => $id, 'method' => 'delete'] );
853
+
854
+		$this->db->where($this->primary_key, $id);
855
+
856
+		if ($this->soft_deletes) {
857
+			$sets = $this->log_user && is_object($this->authenticate)
858
+				? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
859
+				: array($this->soft_delete_key => 1);
860
+
861
+			$result = $this->db->update($this->table_name, $sets);
862
+		} // Hard Delete
863
+		else {
864
+			$result = $this->db->delete($this->table_name);
865
+		}
866
+
867
+		$this->trigger('after_delete', ['id' => $id, 'method' => 'delete', 'result' => $result] );
868
+
869
+		return $result;
870
+	}
871
+
872
+	//--------------------------------------------------------------------
873
+
874
+	public function delete_by()
875
+	{
876
+		$where = func_get_args();
877
+		$this->_set_where($where);
878
+
879
+		$where = $this->trigger('before_delete', ['method' => 'delete_by', 'fields' => $where]);
880
+
881
+		if ($this->soft_deletes) {
882
+			$sets = $this->log_user && is_object($this->authenticate)
883
+				? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
884
+				: array($this->soft_delete_key => 1);
885
+
886
+			$result = $this->db->update($this->table_name, $sets);
887
+		} else {
888
+			$result = $this->db->delete($this->table_name);
889
+		}
890
+
891
+		$this->trigger('after_delete', ['method' => 'delete_by', 'fields' => $where, 'result' => $result] );
892
+
893
+		return $result;
894
+	}
895
+
896
+	//--------------------------------------------------------------------
897
+
898
+	public function delete_many($ids)
899
+	{
900
+		if (!is_array($ids) || count($ids) == 0) return NULL;
901
+
902
+		$ids = $this->trigger('before_delete', ['ids' => $ids, 'method' => 'delete_many'] );
903
+
904
+		$this->db->where_in($this->primary_key, $ids);
905
+
906
+		if ($this->soft_deletes) {
907
+			$sets = $this->log_user && is_object($this->authenticate)
908
+				? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
909
+				: array($this->soft_delete_key => 1);
910
+
911
+			$result = $this->db->update($this->table_name, $sets);
912
+		} else {
913
+			$result = $this->db->delete($this->table_name);
914
+		}
915
+
916
+		$this->trigger('after_delete', ['ids' => $ids, 'method' => 'delete_many', 'result' => $result]);
855 917
 
856
-        if ($this->soft_deletes) {
857
-            $sets = $this->log_user && is_object($this->authenticate)
858
-                ? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
859
-                : array($this->soft_delete_key => 1);
918
+		return $result;
919
+	}
920
+
921
+	//--------------------------------------------------------------------
922
+
923
+	//--------------------------------------------------------------------
924
+	// Scope Methods
925
+	//--------------------------------------------------------------------
926
+
927
+	/**
928
+	 * Sets the value of the soft deletes flag.
929
+	 *
930
+	 * @param  boolean $val If TRUE, should perform a soft delete. If FALSE, a hard delete.
931
+	 */
932
+	public function soft_delete($val = TRUE)
933
+	{
934
+		$this->soft_deletes = $val;
860 935
 
861
-            $result = $this->db->update($this->table_name, $sets);
862
-        } // Hard Delete
863
-        else {
864
-            $result = $this->db->delete($this->table_name);
865
-        }
866
-
867
-        $this->trigger('after_delete', ['id' => $id, 'method' => 'delete', 'result' => $result] );
868
-
869
-        return $result;
870
-    }
871
-
872
-    //--------------------------------------------------------------------
873
-
874
-    public function delete_by()
875
-    {
876
-        $where = func_get_args();
877
-        $this->_set_where($where);
878
-
879
-        $where = $this->trigger('before_delete', ['method' => 'delete_by', 'fields' => $where]);
880
-
881
-        if ($this->soft_deletes) {
882
-            $sets = $this->log_user && is_object($this->authenticate)
883
-                ? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
884
-                : array($this->soft_delete_key => 1);
885
-
886
-            $result = $this->db->update($this->table_name, $sets);
887
-        } else {
888
-            $result = $this->db->delete($this->table_name);
889
-        }
890
-
891
-        $this->trigger('after_delete', ['method' => 'delete_by', 'fields' => $where, 'result' => $result] );
892
-
893
-        return $result;
894
-    }
895
-
896
-    //--------------------------------------------------------------------
897
-
898
-    public function delete_many($ids)
899
-    {
900
-        if (!is_array($ids) || count($ids) == 0) return NULL;
901
-
902
-        $ids = $this->trigger('before_delete', ['ids' => $ids, 'method' => 'delete_many'] );
903
-
904
-        $this->db->where_in($this->primary_key, $ids);
905
-
906
-        if ($this->soft_deletes) {
907
-            $sets = $this->log_user && is_object($this->authenticate)
908
-                ? array($this->soft_delete_key => 1, $this->deleted_by_field => $this->authenticate->id())
909
-                : array($this->soft_delete_key => 1);
910
-
911
-            $result = $this->db->update($this->table_name, $sets);
912
-        } else {
913
-            $result = $this->db->delete($this->table_name);
914
-        }
915
-
916
-        $this->trigger('after_delete', ['ids' => $ids, 'method' => 'delete_many', 'result' => $result]);
917
-
918
-        return $result;
919
-    }
920
-
921
-    //--------------------------------------------------------------------
922
-
923
-    //--------------------------------------------------------------------
924
-    // Scope Methods
925
-    //--------------------------------------------------------------------
926
-
927
-    /**
928
-     * Sets the value of the soft deletes flag.
929
-     *
930
-     * @param  boolean $val If TRUE, should perform a soft delete. If FALSE, a hard delete.
931
-     */
932
-    public function soft_delete($val = TRUE)
933
-    {
934
-        $this->soft_deletes = $val;
935
-
936
-        return $this;
937
-    }
938
-
939
-    //--------------------------------------------------------------------
940
-
941
-    /**
942
-     * Temporarily sets our return type to an array.
943
-     */
944
-    public function as_array()
945
-    {
946
-        $this->temp_return_type = 'array';
947
-
948
-        return $this;
949
-    }
950
-
951
-    //--------------------------------------------------------------------
952
-
953
-    /**
954
-     * Temporarily sets our return type to an object.
955
-     *
956
-     * If $class is provided, the rows will be returned as objects that
957
-     * are instances of that class. $class MUST be an fully qualified
958
-     * class name, meaning that it must include the namespace, if applicable.
959
-     *
960
-     * @param string $class
961
-     * @return $this
962
-     */
963
-    public function as_object($class=null)
964
-    {
965
-        $this->temp_return_type = ! empty($class) ? $class : 'object';
966
-
967
-        return $this;
968
-    }
969
-
970
-    //--------------------------------------------------------------------
971
-
972
-    /**
973
-     * Also fetches deleted items for this request only.
974
-     */
975
-    public function with_deleted()
976
-    {
977
-        $this->temp_with_deleted = TRUE;
978
-
979
-        return $this;
980
-    }
981
-
982
-    //--------------------------------------------------------------------
983
-
984
-    /**
985
-     * Returns whether the current setup will return
986
-     * soft deleted rows.
987
-     *
988
-     * @return bool
989
-     */
990
-    public function get_with_deleted()
991
-    {
992
-        return $this->temp_with_deleted;
993
-    }
994
-
995
-    //--------------------------------------------------------------------
996
-
997
-
998
-    /**
999
-     * Sets the $skip_validation parameter.
1000
-     *
1001
-     * @param bool $skip
1002
-     * @return $this
1003
-     */
1004
-    public function skip_validation($skip = true)
1005
-    {
1006
-        $this->skip_validation = $skip;
1007
-
1008
-        return $this;
1009
-    }
1010
-
1011
-    //--------------------------------------------------------------------
1012
-
1013
-
1014
-    //--------------------------------------------------------------------
1015
-    // Utility Methods
1016
-    //--------------------------------------------------------------------
1017
-
1018
-    /**
1019
-     * Counts number of rows modified by an arbitrary WHERE call.
1020
-     * @return INT
1021
-     */
1022
-    public function count_by()
1023
-    {
1024
-        $where = func_get_args();
1025
-        $this->_set_where($where);
1026
-
1027
-        return $this->db->count_all_results($this->table_name);
1028
-    }
1029
-
1030
-    //--------------------------------------------------------------------
1031
-
1032
-    /**
1033
-     * Counts total number of records, disregarding any previous conditions.
1034
-     *
1035
-     * @return int
1036
-     */
1037
-    public function count_all()
1038
-    {
1039
-        return $this->db->count_all($this->table_name);
1040
-    }
1041
-
1042
-    //--------------------------------------------------------------------
1043
-
1044
-    /**
1045
-     * Getter for the table name.
1046
-     *
1047
-     * @return string The name of the table used by this class.
1048
-     */
1049
-    public function table()
1050
-    {
1051
-        return $this->table_name;
1052
-    }
1053
-
1054
-    //--------------------------------------------------------------------
1055
-
1056
-    /**
1057
-     * Set the return_insert_id value.
1058
-     *
1059
-     * @param  boolean $return If TRUE, insert will return the insert_id.
1060
-     */
1061
-    public function return_insert_id($return = true)
1062
-    {
1063
-        $this->return_insert_id = (bool)$return;
1064
-
1065
-        return $this;
1066
-    }
1067
-
1068
-    //--------------------------------------------------------------------
1069
-
1070
-    /**
1071
-     * A convenience method to return only a single field of the specified row.
1072
-     *
1073
-     * @param mixed $id The primary_key value to match against.
1074
-     * @param string $field The field to search for.
1075
-     *
1076
-     * @return bool|mixed The value of the field.
1077
-     */
1078
-    public function get_field($id = NULL, $field = '')
1079
-    {
1080
-        $this->db->select($field);
1081
-        $this->db->where($this->primary_key, $id);
1082
-        $query = $this->db->get($this->table_name);
1083
-
1084
-        if ($query && $query->num_rows() > 0) {
1085
-            return $query->row()->$field;
1086
-        }
1087
-
1088
-        return FALSE;
1089
-
1090
-    }
1091
-
1092
-    //---------------------------------------------------------------
1093
-
1094
-    /**
1095
-     * Checks whether a field/value pair exists within the table.
1096
-     *
1097
-     * @param string $field The field to search for.
1098
-     * @param string $value The value to match $field against.
1099
-     *
1100
-     * @return bool TRUE/FALSE
1101
-     */
1102
-    public function is_unique($field, $value)
1103
-    {
1104
-        $this->db->where($field, $value);
1105
-        $query = $this->db->get($this->table_name);
1106
-
1107
-        if ($query && $query->num_rows() == 0) {
1108
-            return TRUE;
1109
-        }
1110
-
1111
-        return FALSE;
1112
-
1113
-    }
1114
-
1115
-    //---------------------------------------------------------------
1116
-
1117
-    /**
1118
-     * Adds a field to the protected_attributes array.
1119
-     *
1120
-     * @param $field
1121
-     *
1122
-     * @return mixed
1123
-     */
1124
-    public function protect($field)
1125
-    {
1126
-        $this->protected_attributes[] = $field;
1127
-
1128
-        return $this;
1129
-    }
1130
-
1131
-    //--------------------------------------------------------------------
1132
-
1133
-    /**
1134
-     * Get the field names for this model's table.
1135
-     *
1136
-     * Returns the model's database fields stored in $this->fields
1137
-     * if set, else it tries to retrieve the field list from
1138
-     * $this->db->list_fields($this->table_name);
1139
-     *
1140
-     * @return array    Returns the database fields for this model
1141
-     */
1142
-    public function get_fields()
1143
-    {
1144
-        if (empty($this->fields)) {
1145
-            $this->fields = $this->db->list_fields($this->table_name);
1146
-        }
1147
-
1148
-        return $this->fields;
1149
-    }
1150
-
1151
-    //--------------------------------------------------------------------
1152
-
1153
-    /**
1154
-     * Extracts the model's fields (except the key and those handled by
1155
-     * Observers) from the $post_data and returns an array of name => value pairs
1156
-     *
1157
-     * @param Array $post_data The post data, usually $this->input->post() when called from the controller
1158
-     *
1159
-     * @return Array    An array of name => value pairs containing the data for the model's fields
1160
-     */
1161
-    public function prep_data($post_data)
1162
-    {
1163
-        $data = array();
1164
-        $skippedFields = array();
1165
-
1166
-        if (empty($post_data))
1167
-        {
1168
-            return [];
1169
-        }
1170
-
1171
-        // Though the model doesn't support multiple keys well, $this->key
1172
-        // could be an array or a string...
1173
-        $skippedFields = array_merge($skippedFields, (array)$this->primary_key);
1174
-
1175
-        // Remove any protected attributes
1176
-        $skippedFields = array_merge($skippedFields, $this->protected_attributes);
1177
-
1178
-        $fields = $this->get_fields();
1179
-
1180
-        // If the field is the primary key, one of the created/modified/deleted
1181
-        // fields, or has not been set in the $post_data, skip it
1182
-        foreach ($post_data as $field => $value) {
1183
-            if (in_array($field, $skippedFields) ||
1184
-                ! in_array($field, $fields))
1185
-            {
1186
-                continue;
1187
-            }
1188
-
1189
-            $data[$field] = $value;
1190
-        }
1191
-
1192
-        return $data;
1193
-    }
1194
-
1195
-    //--------------------------------------------------------------------
1196
-
1197
-    /**
1198
-     * Returns the last query string, if available. Simply a wrapper for
1199
-     * CodeIgniter's database method of the same name.
1200
-     *
1201
-     * @return string
1202
-     */
1203
-    public function last_query ()
1204
-    {
1205
-        return $this->db->last_query();
1206
-    }
1207
-
1208
-    //--------------------------------------------------------------------
1209
-
1210
-    /**
1211
-     * Returns the elapsed time for the last query that was executed, if
1212
-     * available, or NULL if not available, like if debug mode is off.
1213
-     *
1214
-     * @return mixed
1215
-     */
1216
-    public function last_query_time ()
1217
-    {
1218
-        $times = $this->db->query_times;
1219
-
1220
-        if (! is_array($this->db->query_times) || ! count($this->db->query_times))
1221
-        {
1222
-            return null;
1223
-        }
1224
-
1225
-        return end($times);
1226
-    }
1227
-
1228
-    //--------------------------------------------------------------------
1229
-
1230
-    //--------------------------------------------------------------------
1231
-    // Observers
1232
-    //--------------------------------------------------------------------
1233
-
1234
-    /**
1235
-     * Sets the created on date for the object based on the
1236
-     * current date/time and date_format. Will not overwrite existing.
1237
-     *
1238
-     * @param array $row The array of data to be inserted
1239
-     *
1240
-     * @return array
1241
-     */
1242
-    public function created_on($row)
1243
-    {
1244
-        if (empty($row['fields']))
1245
-        {
1246
-            return null;
1247
-        }
1248
-
1249
-        $row = $row['fields'];
1250
-
1251
-        // Created_on
1252
-        if (! array_key_exists($this->created_field, $row))
1253
-        {
1254
-            $row[$this->created_field] = $this->set_date();
1255
-        }
1256
-
1257
-        // Created by
1258
-        if ($this->log_user && ! array_key_exists($this->created_by_field, $row) && is_object($this->authenticate))
1259
-        {
1260
-            // If you're here because of an error with $this->authenticate
1261
-            // not being available, it's likely due to you not using
1262
-            // the AuthTrait and/or setting log_user after model is instantiated.
1263
-            $row[$this->created_by_field] = (int)$this->authenticate->id();
1264
-        }
1265
-
1266
-        return $row;
1267
-    } // end created_on()
1268
-
1269
-    //--------------------------------------------------------------------
1270
-
1271
-    /**
1272
-     * Sets the modified_on date for the object based on the
1273
-     * current date/time and date_format. Will not overwrite existing.
1274
-     *
1275
-     * @param array $row The array of data to be inserted
1276
-     *
1277
-     * @return array
1278
-     */
1279
-    public function modified_on($row)
1280
-    {
1281
-        if (empty($row['fields']))
1282
-        {
1283
-            return null;
1284
-        }
1285
-
1286
-        $row = $row['fields'];
1287
-
1288
-        if (is_array($row) && ! array_key_exists($this->modified_field, $row))
1289
-        {
1290
-            $row[$this->modified_field] = $this->set_date();
1291
-        }
1292
-
1293
-        // Modified by
1294
-        if ($this->log_user && ! array_key_exists($this->modified_by_field, $row) && is_object($this->authenticate))
1295
-        {
1296
-            // If you're here because of an error with $this->authenticate
1297
-            // not being available, it's likely due to you not using
1298
-            // the AuthTrait and/or setting log_user after model is instantiated.
1299
-            $row[$this->modified_by_field] = $this->authenticate->id();
1300
-        }
1301
-
1302
-        return $row;
1303
-    }
1304
-
1305
-    //--------------------------------------------------------------------
1306
-
1307
-    //--------------------------------------------------------------------
1308
-    // Internal Methods
1309
-    //--------------------------------------------------------------------
1310
-
1311
-    /**
1312
-     * Set WHERE parameters
1313
-     */
1314
-    protected function _set_where($params)
1315
-    {
1316
-        if (count($params) == 1) {
1317
-            $this->db->where($params[0]);
1318
-        } else {
1319
-            $this->db->where($params[0], $params[1]);
1320
-        }
1321
-    }
1322
-
1323
-    //--------------------------------------------------------------------
1324
-
1325
-    /**
1326
-     * Triggers a model-specific event and call each of it's observers.
1327
-     *
1328
-     * @param string $event The name of the event to trigger
1329
-     * @param mixed $data The data to be passed to the callback functions.
1330
-     *
1331
-     * @return mixed
1332
-     */
1333
-    public function trigger($event, $data = false)
1334
-    {
1335
-        if (! isset($this->$event) || ! is_array($this->$event))
1336
-        {
1337
-            if (isset($data['fields']))
1338
-            {
1339
-                return $data['fields'];
1340
-            }
1341
-
1342
-            return $data;
1343
-        }
1344
-
1345
-        foreach ($this->$event as $method)
1346
-        {
1347
-            if (strpos($method, '('))
1348
-            {
1349
-                preg_match('/([a-zA-Z0-9\_\-]+)(\(([a-zA-Z0-9\_\-\., ]+)\))?/', $method, $matches);
1350
-                $this->callback_parameters = explode(',', $matches[3]);
1351
-            }
1352
-
1353
-            $data = call_user_func_array(array($this, $method), array($data));
1354
-        }
1355
-
1356
-        // In case no method called or method returned
1357
-        // the entire data array, we typically just need the $fields
1358
-        if (isset($data['fields']))
1359
-        {
1360
-            return $data['fields'];
1361
-        }
1362
-
1363
-        // A few methods might need to return 'ids'
1364
-        if (isset($data['ids']))
1365
-        {
1366
-            return $data['ids'];
1367
-        }
1368
-
1369
-        return $data;
1370
-    }
1371
-
1372
-    //--------------------------------------------------------------------
1373
-
1374
-    /**
1375
-     * Validates the data passed into it based upon the form_validation rules
1376
-     * setup in the $this->validate property.
1377
-     *
1378
-     * If $type == 'insert', any additional rules in the class var $insert_validate_rules
1379
-     * for that field will be added to the rules.
1380
-     *
1381
-     * @param  array $data An array of validation rules
1382
-     * @param  string $type Either 'update' or 'insert'.
1383
-     * @return array/bool       The original data or FALSE
1384
-     */
1385
-    public function validate($data, $type = 'update', $skip_validation = null)
1386
-    {
1387
-        $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
1388
-
1389
-        if ($skip_validation) {
1390
-            return $data;
1391
-        }
1392
-
1393
-        // We need the database to be loaded up at this point in case
1394
-        // we want to use callbacks that hit the database.
1395
-        if (empty($this->db))
1396
-        {
1397
-            $this->load->database();
1398
-        }
1399
-
1400
-        if (!empty($this->validation_rules)) {
1401
-            $this->form_validation->set_data($data);
1402
-
1403
-            if (is_array($this->validation_rules)) {
1404
-                // Any insert additions?
1405
-                if ($type == 'insert'
1406
-                    && !empty($this->insert_validate_rules)
1407
-                    && is_array($this->insert_validate_rules)
1408
-                ) {
1409
-                    foreach ($this->validation_rules as &$row) {
1410
-                        if (isset($this->insert_validate_rules[$row['field']])) {
1411
-                            $row ['rules'] .= '|' . $this->insert_validate_rules[$row['field']];
1412
-                        }
1413
-                    }
1414
-                }
1415
-
1416
-                $this->form_validation->set_rules($this->validation_rules);
1417
-
1418
-                if ($this->form_validation->run('', $this) === TRUE) {
1419
-                    return $data;
1420
-                } else {
1421
-                    return FALSE;
1422
-                }
1423
-            } else {
1424
-                if ($this->form_validation->run($this->validate, $this) === TRUE) {
1425
-                    return $data;
1426
-                } else {
1427
-                    return FALSE;
1428
-                }
1429
-            }
1430
-        } else {
1431
-            return $data;
1432
-        }
1433
-    }
1434
-
1435
-    //--------------------------------------------------------------------
1436
-
1437
-    /**
1438
-     * Protect attributes by removing them from $row array. Useful for
1439
-     * removing id, or submit buttons names if you simply throw your $_POST
1440
-     * array at your model. :)
1441
-     *
1442
-     * @param object /array $row The value pair item to remove.
1443
-     */
1444
-    public function protect_attributes($row)
1445
-    {
1446
-        foreach ($this->protected_attributes as $attr) {
1447
-            if (is_object($row)) {
1448
-                unset($row->$attr);
1449
-            } else {
1450
-                unset($row[$attr]);
1451
-            }
1452
-        }
1453
-
1454
-        return $row;
1455
-    }
1456
-
1457
-    //--------------------------------------------------------------------
1458
-
1459
-    /**
1460
-     * A utility function to allow child models to use the type of
1461
-     * date/time format that they prefer. This is primarily used for
1462
-     * setting created_on and modified_on values, but can be used by
1463
-     * inheriting classes.
1464
-     *
1465
-     * The available time formats are:
1466
-     * * 'int'      - Stores the date as an integer timestamp.
1467
-     * * 'datetime' - Stores the date and time in the SQL datetime format.
1468
-     * * 'date'     - Stores teh date (only) in the SQL date format.
1469
-     *
1470
-     * @param mixed $user_date An optional PHP timestamp to be converted.
1471
-     *
1472
-     * @access protected
1473
-     *
1474
-     * @return int|null|string The current/user time converted to the proper format.
1475
-     */
1476
-    protected function set_date($user_date = NULL)
1477
-    {
1478
-        $curr_date = !empty($user_date) ? $user_date : time();
1479
-
1480
-        switch ($this->date_format) {
1481
-            case 'int':
1482
-                return $curr_date;
1483
-                break;
1484
-            case 'datetime':
1485
-                return date('Y-m-d H:i:s', $curr_date);
1486
-                break;
1487
-            case 'date':
1488
-                return date('Y-m-d', $curr_date);
1489
-                break;
1490
-        }
1491
-
1492
-    }//end set_date()
1493
-
1494
-    //--------------------------------------------------------------------
1495
-
1496
-    /**
1497
-     * Returns an array containing the 'code' and 'message' of the
1498
-     * database's error, as provided by CI's database drivers.
1499
-     *
1500
-     * @return mixed
1501
-     */
1502
-    public function error($db_array_only=false)
1503
-    {
1504
-        // Send any validation errors if we have any.
1505
-        if (function_exists('validation_errors') && validation_errors() && ! $db_array_only)
1506
-        {
1507
-            return validation_errors();
1508
-        }
1509
-
1510
-        // No validation errors? Return the db error.
1511
-        $error = $this->db->error();
1512
-
1513
-        if ($db_array_only)
1514
-        {
1515
-            return $error;
1516
-        }
1517
-
1518
-        if (! empty($error['code']))
1519
-        {
1520
-            return "Database Error {$error['code']}: {$error['message']}.";
1521
-        }
1522
-
1523
-        // No errors found.
1524
-        return '';
1525
-    }
1526
-
1527
-    //--------------------------------------------------------------------
1528
-
1529
-    //--------------------------------------------------------------------
1530
-    // Magic Methods
1531
-    //--------------------------------------------------------------------
1532
-
1533
-    /**
1534
-     * __get magic
1535
-     *
1536
-     * Allows models to access CI's loaded classes using the same
1537
-     * syntax as controllers.
1538
-     *
1539
-     * This is the same as what CI's model uses, but we keep it
1540
-     * here since that's the ONLY thing that CI's model does.
1541
-     *
1542
-     * @param    string $key
1543
-     */
1544
-    public function __get($key)
1545
-    {
1546
-        // Give them first crack at any protected class vars
1547
-        if (isset($this->$key))
1548
-        {
1549
-            return $this->$key;
1550
-        }
1551
-
1552
-        // Debugging note:
1553
-        //	If you're here because you're getting an error message
1554
-        //	saying 'Undefined Property: system/core/Model.php', it's
1555
-        //	most likely a typo in your model code.
1556
-        return get_instance()->$key;
1557
-    }
1558
-
1559
-    //--------------------------------------------------------------------
1560
-
1561
-    /**
1562
-     * Provide direct access to any of CodeIgniter's DB methods but
1563
-     * make it look like it's part of the class, purely for convenience.
1564
-     *
1565
-     * @param $name
1566
-     * @param $params
1567
-     */
1568
-    public function __call($name, $params)
1569
-    {
1570
-        if (method_exists($this->db, $name))
1571
-        {
1572
-            call_user_func_array([$this->db, $name], $params);
1573
-            return $this;
1574
-        }
1575
-    }
1576
-
1577
-    //--------------------------------------------------------------------
936
+		return $this;
937
+	}
938
+
939
+	//--------------------------------------------------------------------
940
+
941
+	/**
942
+	 * Temporarily sets our return type to an array.
943
+	 */
944
+	public function as_array()
945
+	{
946
+		$this->temp_return_type = 'array';
947
+
948
+		return $this;
949
+	}
950
+
951
+	//--------------------------------------------------------------------
952
+
953
+	/**
954
+	 * Temporarily sets our return type to an object.
955
+	 *
956
+	 * If $class is provided, the rows will be returned as objects that
957
+	 * are instances of that class. $class MUST be an fully qualified
958
+	 * class name, meaning that it must include the namespace, if applicable.
959
+	 *
960
+	 * @param string $class
961
+	 * @return $this
962
+	 */
963
+	public function as_object($class=null)
964
+	{
965
+		$this->temp_return_type = ! empty($class) ? $class : 'object';
966
+
967
+		return $this;
968
+	}
969
+
970
+	//--------------------------------------------------------------------
971
+
972
+	/**
973
+	 * Also fetches deleted items for this request only.
974
+	 */
975
+	public function with_deleted()
976
+	{
977
+		$this->temp_with_deleted = TRUE;
978
+
979
+		return $this;
980
+	}
981
+
982
+	//--------------------------------------------------------------------
983
+
984
+	/**
985
+	 * Returns whether the current setup will return
986
+	 * soft deleted rows.
987
+	 *
988
+	 * @return bool
989
+	 */
990
+	public function get_with_deleted()
991
+	{
992
+		return $this->temp_with_deleted;
993
+	}
994
+
995
+	//--------------------------------------------------------------------
996
+
997
+
998
+	/**
999
+	 * Sets the $skip_validation parameter.
1000
+	 *
1001
+	 * @param bool $skip
1002
+	 * @return $this
1003
+	 */
1004
+	public function skip_validation($skip = true)
1005
+	{
1006
+		$this->skip_validation = $skip;
1007
+
1008
+		return $this;
1009
+	}
1010
+
1011
+	//--------------------------------------------------------------------
1012
+
1013
+
1014
+	//--------------------------------------------------------------------
1015
+	// Utility Methods
1016
+	//--------------------------------------------------------------------
1017
+
1018
+	/**
1019
+	 * Counts number of rows modified by an arbitrary WHERE call.
1020
+	 * @return INT
1021
+	 */
1022
+	public function count_by()
1023
+	{
1024
+		$where = func_get_args();
1025
+		$this->_set_where($where);
1026
+
1027
+		return $this->db->count_all_results($this->table_name);
1028
+	}
1029
+
1030
+	//--------------------------------------------------------------------
1031
+
1032
+	/**
1033
+	 * Counts total number of records, disregarding any previous conditions.
1034
+	 *
1035
+	 * @return int
1036
+	 */
1037
+	public function count_all()
1038
+	{
1039
+		return $this->db->count_all($this->table_name);
1040
+	}
1041
+
1042
+	//--------------------------------------------------------------------
1043
+
1044
+	/**
1045
+	 * Getter for the table name.
1046
+	 *
1047
+	 * @return string The name of the table used by this class.
1048
+	 */
1049
+	public function table()
1050
+	{
1051
+		return $this->table_name;
1052
+	}
1053
+
1054
+	//--------------------------------------------------------------------
1055
+
1056
+	/**
1057
+	 * Set the return_insert_id value.
1058
+	 *
1059
+	 * @param  boolean $return If TRUE, insert will return the insert_id.
1060
+	 */
1061
+	public function return_insert_id($return = true)
1062
+	{
1063
+		$this->return_insert_id = (bool)$return;
1064
+
1065
+		return $this;
1066
+	}
1067
+
1068
+	//--------------------------------------------------------------------
1069
+
1070
+	/**
1071
+	 * A convenience method to return only a single field of the specified row.
1072
+	 *
1073
+	 * @param mixed $id The primary_key value to match against.
1074
+	 * @param string $field The field to search for.
1075
+	 *
1076
+	 * @return bool|mixed The value of the field.
1077
+	 */
1078
+	public function get_field($id = NULL, $field = '')
1079
+	{
1080
+		$this->db->select($field);
1081
+		$this->db->where($this->primary_key, $id);
1082
+		$query = $this->db->get($this->table_name);
1083
+
1084
+		if ($query && $query->num_rows() > 0) {
1085
+			return $query->row()->$field;
1086
+		}
1087
+
1088
+		return FALSE;
1089
+
1090
+	}
1091
+
1092
+	//---------------------------------------------------------------
1093
+
1094
+	/**
1095
+	 * Checks whether a field/value pair exists within the table.
1096
+	 *
1097
+	 * @param string $field The field to search for.
1098
+	 * @param string $value The value to match $field against.
1099
+	 *
1100
+	 * @return bool TRUE/FALSE
1101
+	 */
1102
+	public function is_unique($field, $value)
1103
+	{
1104
+		$this->db->where($field, $value);
1105
+		$query = $this->db->get($this->table_name);
1106
+
1107
+		if ($query && $query->num_rows() == 0) {
1108
+			return TRUE;
1109
+		}
1110
+
1111
+		return FALSE;
1112
+
1113
+	}
1114
+
1115
+	//---------------------------------------------------------------
1116
+
1117
+	/**
1118
+	 * Adds a field to the protected_attributes array.
1119
+	 *
1120
+	 * @param $field
1121
+	 *
1122
+	 * @return mixed
1123
+	 */
1124
+	public function protect($field)
1125
+	{
1126
+		$this->protected_attributes[] = $field;
1127
+
1128
+		return $this;
1129
+	}
1130
+
1131
+	//--------------------------------------------------------------------
1132
+
1133
+	/**
1134
+	 * Get the field names for this model's table.
1135
+	 *
1136
+	 * Returns the model's database fields stored in $this->fields
1137
+	 * if set, else it tries to retrieve the field list from
1138
+	 * $this->db->list_fields($this->table_name);
1139
+	 *
1140
+	 * @return array    Returns the database fields for this model
1141
+	 */
1142
+	public function get_fields()
1143
+	{
1144
+		if (empty($this->fields)) {
1145
+			$this->fields = $this->db->list_fields($this->table_name);
1146
+		}
1147
+
1148
+		return $this->fields;
1149
+	}
1150
+
1151
+	//--------------------------------------------------------------------
1152
+
1153
+	/**
1154
+	 * Extracts the model's fields (except the key and those handled by
1155
+	 * Observers) from the $post_data and returns an array of name => value pairs
1156
+	 *
1157
+	 * @param Array $post_data The post data, usually $this->input->post() when called from the controller
1158
+	 *
1159
+	 * @return Array    An array of name => value pairs containing the data for the model's fields
1160
+	 */
1161
+	public function prep_data($post_data)
1162
+	{
1163
+		$data = array();
1164
+		$skippedFields = array();
1165
+
1166
+		if (empty($post_data))
1167
+		{
1168
+			return [];
1169
+		}
1170
+
1171
+		// Though the model doesn't support multiple keys well, $this->key
1172
+		// could be an array or a string...
1173
+		$skippedFields = array_merge($skippedFields, (array)$this->primary_key);
1174
+
1175
+		// Remove any protected attributes
1176
+		$skippedFields = array_merge($skippedFields, $this->protected_attributes);
1177
+
1178
+		$fields = $this->get_fields();
1179
+
1180
+		// If the field is the primary key, one of the created/modified/deleted
1181
+		// fields, or has not been set in the $post_data, skip it
1182
+		foreach ($post_data as $field => $value) {
1183
+			if (in_array($field, $skippedFields) ||
1184
+				! in_array($field, $fields))
1185
+			{
1186
+				continue;
1187
+			}
1188
+
1189
+			$data[$field] = $value;
1190
+		}
1191
+
1192
+		return $data;
1193
+	}
1194
+
1195
+	//--------------------------------------------------------------------
1196
+
1197
+	/**
1198
+	 * Returns the last query string, if available. Simply a wrapper for
1199
+	 * CodeIgniter's database method of the same name.
1200
+	 *
1201
+	 * @return string
1202
+	 */
1203
+	public function last_query ()
1204
+	{
1205
+		return $this->db->last_query();
1206
+	}
1207
+
1208
+	//--------------------------------------------------------------------
1209
+
1210
+	/**
1211
+	 * Returns the elapsed time for the last query that was executed, if
1212
+	 * available, or NULL if not available, like if debug mode is off.
1213
+	 *
1214
+	 * @return mixed
1215
+	 */
1216
+	public function last_query_time ()
1217
+	{
1218
+		$times = $this->db->query_times;
1219
+
1220
+		if (! is_array($this->db->query_times) || ! count($this->db->query_times))
1221
+		{
1222
+			return null;
1223
+		}
1224
+
1225
+		return end($times);
1226
+	}
1227
+
1228
+	//--------------------------------------------------------------------
1229
+
1230
+	//--------------------------------------------------------------------
1231
+	// Observers
1232
+	//--------------------------------------------------------------------
1233
+
1234
+	/**
1235
+	 * Sets the created on date for the object based on the
1236
+	 * current date/time and date_format. Will not overwrite existing.
1237
+	 *
1238
+	 * @param array $row The array of data to be inserted
1239
+	 *
1240
+	 * @return array
1241
+	 */
1242
+	public function created_on($row)
1243
+	{
1244
+		if (empty($row['fields']))
1245
+		{
1246
+			return null;
1247
+		}
1248
+
1249
+		$row = $row['fields'];
1250
+
1251
+		// Created_on
1252
+		if (! array_key_exists($this->created_field, $row))
1253
+		{
1254
+			$row[$this->created_field] = $this->set_date();
1255
+		}
1256
+
1257
+		// Created by
1258
+		if ($this->log_user && ! array_key_exists($this->created_by_field, $row) && is_object($this->authenticate))
1259
+		{
1260
+			// If you're here because of an error with $this->authenticate
1261
+			// not being available, it's likely due to you not using
1262
+			// the AuthTrait and/or setting log_user after model is instantiated.
1263
+			$row[$this->created_by_field] = (int)$this->authenticate->id();
1264
+		}
1265
+
1266
+		return $row;
1267
+	} // end created_on()
1268
+
1269
+	//--------------------------------------------------------------------
1270
+
1271
+	/**
1272
+	 * Sets the modified_on date for the object based on the
1273
+	 * current date/time and date_format. Will not overwrite existing.
1274
+	 *
1275
+	 * @param array $row The array of data to be inserted
1276
+	 *
1277
+	 * @return array
1278
+	 */
1279
+	public function modified_on($row)
1280
+	{
1281
+		if (empty($row['fields']))
1282
+		{
1283
+			return null;
1284
+		}
1285
+
1286
+		$row = $row['fields'];
1287
+
1288
+		if (is_array($row) && ! array_key_exists($this->modified_field, $row))
1289
+		{
1290
+			$row[$this->modified_field] = $this->set_date();
1291
+		}
1292
+
1293
+		// Modified by
1294
+		if ($this->log_user && ! array_key_exists($this->modified_by_field, $row) && is_object($this->authenticate))
1295
+		{
1296
+			// If you're here because of an error with $this->authenticate
1297
+			// not being available, it's likely due to you not using
1298
+			// the AuthTrait and/or setting log_user after model is instantiated.
1299
+			$row[$this->modified_by_field] = $this->authenticate->id();
1300
+		}
1301
+
1302
+		return $row;
1303
+	}
1304
+
1305
+	//--------------------------------------------------------------------
1306
+
1307
+	//--------------------------------------------------------------------
1308
+	// Internal Methods
1309
+	//--------------------------------------------------------------------
1310
+
1311
+	/**
1312
+	 * Set WHERE parameters
1313
+	 */
1314
+	protected function _set_where($params)
1315
+	{
1316
+		if (count($params) == 1) {
1317
+			$this->db->where($params[0]);
1318
+		} else {
1319
+			$this->db->where($params[0], $params[1]);
1320
+		}
1321
+	}
1322
+
1323
+	//--------------------------------------------------------------------
1324
+
1325
+	/**
1326
+	 * Triggers a model-specific event and call each of it's observers.
1327
+	 *
1328
+	 * @param string $event The name of the event to trigger
1329
+	 * @param mixed $data The data to be passed to the callback functions.
1330
+	 *
1331
+	 * @return mixed
1332
+	 */
1333
+	public function trigger($event, $data = false)
1334
+	{
1335
+		if (! isset($this->$event) || ! is_array($this->$event))
1336
+		{
1337
+			if (isset($data['fields']))
1338
+			{
1339
+				return $data['fields'];
1340
+			}
1341
+
1342
+			return $data;
1343
+		}
1344
+
1345
+		foreach ($this->$event as $method)
1346
+		{
1347
+			if (strpos($method, '('))
1348
+			{
1349
+				preg_match('/([a-zA-Z0-9\_\-]+)(\(([a-zA-Z0-9\_\-\., ]+)\))?/', $method, $matches);
1350
+				$this->callback_parameters = explode(',', $matches[3]);
1351
+			}
1352
+
1353
+			$data = call_user_func_array(array($this, $method), array($data));
1354
+		}
1355
+
1356
+		// In case no method called or method returned
1357
+		// the entire data array, we typically just need the $fields
1358
+		if (isset($data['fields']))
1359
+		{
1360
+			return $data['fields'];
1361
+		}
1362
+
1363
+		// A few methods might need to return 'ids'
1364
+		if (isset($data['ids']))
1365
+		{
1366
+			return $data['ids'];
1367
+		}
1368
+
1369
+		return $data;
1370
+	}
1371
+
1372
+	//--------------------------------------------------------------------
1373
+
1374
+	/**
1375
+	 * Validates the data passed into it based upon the form_validation rules
1376
+	 * setup in the $this->validate property.
1377
+	 *
1378
+	 * If $type == 'insert', any additional rules in the class var $insert_validate_rules
1379
+	 * for that field will be added to the rules.
1380
+	 *
1381
+	 * @param  array $data An array of validation rules
1382
+	 * @param  string $type Either 'update' or 'insert'.
1383
+	 * @return array/bool       The original data or FALSE
1384
+	 */
1385
+	public function validate($data, $type = 'update', $skip_validation = null)
1386
+	{
1387
+		$skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
1388
+
1389
+		if ($skip_validation) {
1390
+			return $data;
1391
+		}
1392
+
1393
+		// We need the database to be loaded up at this point in case
1394
+		// we want to use callbacks that hit the database.
1395
+		if (empty($this->db))
1396
+		{
1397
+			$this->load->database();
1398
+		}
1399
+
1400
+		if (!empty($this->validation_rules)) {
1401
+			$this->form_validation->set_data($data);
1402
+
1403
+			if (is_array($this->validation_rules)) {
1404
+				// Any insert additions?
1405
+				if ($type == 'insert'
1406
+					&& !empty($this->insert_validate_rules)
1407
+					&& is_array($this->insert_validate_rules)
1408
+				) {
1409
+					foreach ($this->validation_rules as &$row) {
1410
+						if (isset($this->insert_validate_rules[$row['field']])) {
1411
+							$row ['rules'] .= '|' . $this->insert_validate_rules[$row['field']];
1412
+						}
1413
+					}
1414
+				}
1415
+
1416
+				$this->form_validation->set_rules($this->validation_rules);
1417
+
1418
+				if ($this->form_validation->run('', $this) === TRUE) {
1419
+					return $data;
1420
+				} else {
1421
+					return FALSE;
1422
+				}
1423
+			} else {
1424
+				if ($this->form_validation->run($this->validate, $this) === TRUE) {
1425
+					return $data;
1426
+				} else {
1427
+					return FALSE;
1428
+				}
1429
+			}
1430
+		} else {
1431
+			return $data;
1432
+		}
1433
+	}
1434
+
1435
+	//--------------------------------------------------------------------
1436
+
1437
+	/**
1438
+	 * Protect attributes by removing them from $row array. Useful for
1439
+	 * removing id, or submit buttons names if you simply throw your $_POST
1440
+	 * array at your model. :)
1441
+	 *
1442
+	 * @param object /array $row The value pair item to remove.
1443
+	 */
1444
+	public function protect_attributes($row)
1445
+	{
1446
+		foreach ($this->protected_attributes as $attr) {
1447
+			if (is_object($row)) {
1448
+				unset($row->$attr);
1449
+			} else {
1450
+				unset($row[$attr]);
1451
+			}
1452
+		}
1453
+
1454
+		return $row;
1455
+	}
1456
+
1457
+	//--------------------------------------------------------------------
1458
+
1459
+	/**
1460
+	 * A utility function to allow child models to use the type of
1461
+	 * date/time format that they prefer. This is primarily used for
1462
+	 * setting created_on and modified_on values, but can be used by
1463
+	 * inheriting classes.
1464
+	 *
1465
+	 * The available time formats are:
1466
+	 * * 'int'      - Stores the date as an integer timestamp.
1467
+	 * * 'datetime' - Stores the date and time in the SQL datetime format.
1468
+	 * * 'date'     - Stores teh date (only) in the SQL date format.
1469
+	 *
1470
+	 * @param mixed $user_date An optional PHP timestamp to be converted.
1471
+	 *
1472
+	 * @access protected
1473
+	 *
1474
+	 * @return int|null|string The current/user time converted to the proper format.
1475
+	 */
1476
+	protected function set_date($user_date = NULL)
1477
+	{
1478
+		$curr_date = !empty($user_date) ? $user_date : time();
1479
+
1480
+		switch ($this->date_format) {
1481
+			case 'int':
1482
+				return $curr_date;
1483
+				break;
1484
+			case 'datetime':
1485
+				return date('Y-m-d H:i:s', $curr_date);
1486
+				break;
1487
+			case 'date':
1488
+				return date('Y-m-d', $curr_date);
1489
+				break;
1490
+		}
1491
+
1492
+	}//end set_date()
1493
+
1494
+	//--------------------------------------------------------------------
1495
+
1496
+	/**
1497
+	 * Returns an array containing the 'code' and 'message' of the
1498
+	 * database's error, as provided by CI's database drivers.
1499
+	 *
1500
+	 * @return mixed
1501
+	 */
1502
+	public function error($db_array_only=false)
1503
+	{
1504
+		// Send any validation errors if we have any.
1505
+		if (function_exists('validation_errors') && validation_errors() && ! $db_array_only)
1506
+		{
1507
+			return validation_errors();
1508
+		}
1509
+
1510
+		// No validation errors? Return the db error.
1511
+		$error = $this->db->error();
1512
+
1513
+		if ($db_array_only)
1514
+		{
1515
+			return $error;
1516
+		}
1517
+
1518
+		if (! empty($error['code']))
1519
+		{
1520
+			return "Database Error {$error['code']}: {$error['message']}.";
1521
+		}
1522
+
1523
+		// No errors found.
1524
+		return '';
1525
+	}
1526
+
1527
+	//--------------------------------------------------------------------
1528
+
1529
+	//--------------------------------------------------------------------
1530
+	// Magic Methods
1531
+	//--------------------------------------------------------------------
1532
+
1533
+	/**
1534
+	 * __get magic
1535
+	 *
1536
+	 * Allows models to access CI's loaded classes using the same
1537
+	 * syntax as controllers.
1538
+	 *
1539
+	 * This is the same as what CI's model uses, but we keep it
1540
+	 * here since that's the ONLY thing that CI's model does.
1541
+	 *
1542
+	 * @param    string $key
1543
+	 */
1544
+	public function __get($key)
1545
+	{
1546
+		// Give them first crack at any protected class vars
1547
+		if (isset($this->$key))
1548
+		{
1549
+			return $this->$key;
1550
+		}
1551
+
1552
+		// Debugging note:
1553
+		//	If you're here because you're getting an error message
1554
+		//	saying 'Undefined Property: system/core/Model.php', it's
1555
+		//	most likely a typo in your model code.
1556
+		return get_instance()->$key;
1557
+	}
1558
+
1559
+	//--------------------------------------------------------------------
1560
+
1561
+	/**
1562
+	 * Provide direct access to any of CodeIgniter's DB methods but
1563
+	 * make it look like it's part of the class, purely for convenience.
1564
+	 *
1565
+	 * @param $name
1566
+	 * @param $params
1567
+	 */
1568
+	public function __call($name, $params)
1569
+	{
1570
+		if (method_exists($this->db, $name))
1571
+		{
1572
+			call_user_func_array([$this->db, $name], $params);
1573
+			return $this;
1574
+		}
1575
+	}
1576
+
1577
+	//--------------------------------------------------------------------
1578 1578
 
1579 1579
 
1580 1580
 }
Please login to merge, or discard this patch.
Spacing   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
         $this->temp_return_type = $this->return_type;
302 302
 
303 303
         // Make sure our database is loaded
304
-        if (!is_null($db)) {
304
+        if ( ! is_null($db)) {
305 305
             $this->db = $db;
306 306
         }
307 307
         else {
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
         }
311 311
 
312 312
         // Do we have a form_validation library?
313
-        if (! is_null($form_validation)) {
313
+        if ( ! is_null($form_validation)) {
314 314
             $this->form_validation = $form_validation;
315 315
         }
316 316
         else {
@@ -480,7 +480,7 @@  discard block
 block discarded – undo
480 480
 
481 481
         if (is_array($rows)) {
482 482
             foreach ($rows as $key => &$row) {
483
-                $row = $this->trigger('after_find', ['method' => 'find_all', 'fields' => $row] );
483
+                $row = $this->trigger('after_find', ['method' => 'find_all', 'fields' => $row]);
484 484
             }
485 485
         }
486 486
 
@@ -510,7 +510,7 @@  discard block
 block discarded – undo
510 510
         if ($data !== FALSE) {
511 511
             $data = $this->trigger('before_insert', ['method' => 'insert', 'fields' => $data]);
512 512
 
513
-            $this->db->insert($this->table_name, $this->prep_data($data) );
513
+            $this->db->insert($this->table_name, $this->prep_data($data));
514 514
 
515 515
             if ($this->return_insert_id) {
516 516
                 $id = $this->db->insert_id();
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
 
556 556
         if ($data !== FALSE) {
557 557
             $data['batch'] = true;
558
-            $data = $this->trigger('before_insert', ['method' => 'insert_batch', 'fields' => $data] );
558
+            $data = $this->trigger('before_insert', ['method' => 'insert_batch', 'fields' => $data]);
559 559
             unset($data['batch']);
560 560
 
561 561
             return $this->db->insert_batch($this->table_name, $data);
@@ -577,7 +577,7 @@  discard block
 block discarded – undo
577 577
      * @param null $skip_validation
578 578
      * @return bool
579 579
      */
580
-    public function replace($data, $skip_validation=null)
580
+    public function replace($data, $skip_validation = null)
581 581
     {
582 582
         $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
583 583
 
@@ -624,10 +624,10 @@  discard block
 block discarded – undo
624 624
         // Will be false if it didn't validate.
625 625
         if ($data !== FALSE) {
626 626
             
627
-            $data = $this->trigger('before_update', ['id' => $id, 'method' =>'update', 'fields' => $data] );
627
+            $data = $this->trigger('before_update', ['id' => $id, 'method' =>'update', 'fields' => $data]);
628 628
             
629 629
             $this->db->where($this->primary_key, $id);
630
-            $this->db->set( $this->prep_data($data) );
630
+            $this->db->set($this->prep_data($data));
631 631
             $result = $this->db->update($this->table_name);
632 632
 
633 633
             $this->trigger('after_update', ['id' => $id, 'fields' => $data, 'result' => $result, 'method' => 'update']);
@@ -666,7 +666,7 @@  discard block
 block discarded – undo
666 666
     public function update_batch($data, $where_key)
667 667
     {
668 668
         foreach ($data as &$row) {
669
-            $row = $this->trigger('before_update', ['method' => 'update_batch', 'fields' => $row] );
669
+            $row = $this->trigger('before_update', ['method' => 'update_batch', 'fields' => $row]);
670 670
         }
671 671
 
672 672
         $result = $this->db->update_batch($this->table_name, $data, $where_key);
@@ -700,7 +700,7 @@  discard block
 block discarded – undo
700 700
      */
701 701
     public function update_many($ids, $data, $skip_validation = null)
702 702
     {
703
-        if (!is_array($ids) || count($ids) == 0) return NULL;
703
+        if ( ! is_array($ids) || count($ids) == 0) return NULL;
704 704
 
705 705
         $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
706 706
 
@@ -754,10 +754,10 @@  discard block
 block discarded – undo
754 754
 
755 755
         // Will be false if it didn't validate.
756 756
         if ($this->validate($data) !== FALSE) {
757
-            $this->db->set( $this->prep_data($data) );
757
+            $this->db->set($this->prep_data($data));
758 758
             $result = $this->db->update($this->table_name);
759 759
 
760
-            $this->trigger('after_update', ['method' => 'update_by', 'fields' => $data, 'result' => $result] );
760
+            $this->trigger('after_update', ['method' => 'update_by', 'fields' => $data, 'result' => $result]);
761 761
 
762 762
             return $result;
763 763
         } else {
@@ -776,7 +776,7 @@  discard block
 block discarded – undo
776 776
      */
777 777
     public function update_all($data, $skip_validation = FALSE)
778 778
     {
779
-        $data = $this->trigger('before_update', ['method' => 'update_all', 'fields' => $data] );
779
+        $data = $this->trigger('before_update', ['method' => 'update_all', 'fields' => $data]);
780 780
 
781 781
         $skip_validation = is_null($skip_validation) ? $this->skip_validation : $skip_validation;
782 782
 
@@ -786,10 +786,10 @@  discard block
 block discarded – undo
786 786
 
787 787
         // Will be false if it didn't validate.
788 788
         if ($data !== FALSE) {
789
-            $this->db->set( $this->prep_data($data) );
789
+            $this->db->set($this->prep_data($data));
790 790
             $result = $this->db->update($this->table_name);
791 791
 
792
-            $this->trigger('after_update', ['method' => 'update_all', 'fields' => $data, 'result' => $result] );
792
+            $this->trigger('after_update', ['method' => 'update_all', 'fields' => $data, 'result' => $result]);
793 793
 
794 794
             return $result;
795 795
         } else {
@@ -808,9 +808,9 @@  discard block
 block discarded – undo
808 808
      * @param int $value
809 809
      * @return mixed
810 810
      */
811
-    public function increment($id, $field, $value=1)
811
+    public function increment($id, $field, $value = 1)
812 812
     {
813
-        $value = (int)abs($value);
813
+        $value = (int) abs($value);
814 814
 
815 815
         $this->db->where($this->primary_key, $id);
816 816
         $this->db->set($field, "{$field}+{$value}", false);
@@ -829,9 +829,9 @@  discard block
 block discarded – undo
829 829
      * @param int $value
830 830
      * @return mixed
831 831
      */
832
-    public function decrement($id, $field, $value=1)
832
+    public function decrement($id, $field, $value = 1)
833 833
     {
834
-        $value = (int)abs($value);
834
+        $value = (int) abs($value);
835 835
 
836 836
         $this->db->where($this->primary_key, $id);
837 837
         $this->db->set($field, "{$field}-{$value}", false);
@@ -849,7 +849,7 @@  discard block
 block discarded – undo
849 849
      */
850 850
     public function delete($id)
851 851
     {
852
-        $this->trigger('before_delete', ['id' => $id, 'method' => 'delete'] );
852
+        $this->trigger('before_delete', ['id' => $id, 'method' => 'delete']);
853 853
 
854 854
         $this->db->where($this->primary_key, $id);
855 855
 
@@ -864,7 +864,7 @@  discard block
 block discarded – undo
864 864
             $result = $this->db->delete($this->table_name);
865 865
         }
866 866
 
867
-        $this->trigger('after_delete', ['id' => $id, 'method' => 'delete', 'result' => $result] );
867
+        $this->trigger('after_delete', ['id' => $id, 'method' => 'delete', 'result' => $result]);
868 868
 
869 869
         return $result;
870 870
     }
@@ -888,7 +888,7 @@  discard block
 block discarded – undo
888 888
             $result = $this->db->delete($this->table_name);
889 889
         }
890 890
 
891
-        $this->trigger('after_delete', ['method' => 'delete_by', 'fields' => $where, 'result' => $result] );
891
+        $this->trigger('after_delete', ['method' => 'delete_by', 'fields' => $where, 'result' => $result]);
892 892
 
893 893
         return $result;
894 894
     }
@@ -897,9 +897,9 @@  discard block
 block discarded – undo
897 897
 
898 898
     public function delete_many($ids)
899 899
     {
900
-        if (!is_array($ids) || count($ids) == 0) return NULL;
900
+        if ( ! is_array($ids) || count($ids) == 0) return NULL;
901 901
 
902
-        $ids = $this->trigger('before_delete', ['ids' => $ids, 'method' => 'delete_many'] );
902
+        $ids = $this->trigger('before_delete', ['ids' => $ids, 'method' => 'delete_many']);
903 903
 
904 904
         $this->db->where_in($this->primary_key, $ids);
905 905
 
@@ -960,7 +960,7 @@  discard block
 block discarded – undo
960 960
      * @param string $class
961 961
      * @return $this
962 962
      */
963
-    public function as_object($class=null)
963
+    public function as_object($class = null)
964 964
     {
965 965
         $this->temp_return_type = ! empty($class) ? $class : 'object';
966 966
 
@@ -1060,7 +1060,7 @@  discard block
 block discarded – undo
1060 1060
      */
1061 1061
     public function return_insert_id($return = true)
1062 1062
     {
1063
-        $this->return_insert_id = (bool)$return;
1063
+        $this->return_insert_id = (bool) $return;
1064 1064
 
1065 1065
         return $this;
1066 1066
     }
@@ -1170,7 +1170,7 @@  discard block
 block discarded – undo
1170 1170
 
1171 1171
         // Though the model doesn't support multiple keys well, $this->key
1172 1172
         // could be an array or a string...
1173
-        $skippedFields = array_merge($skippedFields, (array)$this->primary_key);
1173
+        $skippedFields = array_merge($skippedFields, (array) $this->primary_key);
1174 1174
 
1175 1175
         // Remove any protected attributes
1176 1176
         $skippedFields = array_merge($skippedFields, $this->protected_attributes);
@@ -1200,7 +1200,7 @@  discard block
 block discarded – undo
1200 1200
      *
1201 1201
      * @return string
1202 1202
      */
1203
-    public function last_query ()
1203
+    public function last_query()
1204 1204
     {
1205 1205
         return $this->db->last_query();
1206 1206
     }
@@ -1213,11 +1213,11 @@  discard block
 block discarded – undo
1213 1213
      *
1214 1214
      * @return mixed
1215 1215
      */
1216
-    public function last_query_time ()
1216
+    public function last_query_time()
1217 1217
     {
1218 1218
         $times = $this->db->query_times;
1219 1219
 
1220
-        if (! is_array($this->db->query_times) || ! count($this->db->query_times))
1220
+        if ( ! is_array($this->db->query_times) || ! count($this->db->query_times))
1221 1221
         {
1222 1222
             return null;
1223 1223
         }
@@ -1249,7 +1249,7 @@  discard block
 block discarded – undo
1249 1249
         $row = $row['fields'];
1250 1250
 
1251 1251
         // Created_on
1252
-        if (! array_key_exists($this->created_field, $row))
1252
+        if ( ! array_key_exists($this->created_field, $row))
1253 1253
         {
1254 1254
             $row[$this->created_field] = $this->set_date();
1255 1255
         }
@@ -1260,7 +1260,7 @@  discard block
 block discarded – undo
1260 1260
             // If you're here because of an error with $this->authenticate
1261 1261
             // not being available, it's likely due to you not using
1262 1262
             // the AuthTrait and/or setting log_user after model is instantiated.
1263
-            $row[$this->created_by_field] = (int)$this->authenticate->id();
1263
+            $row[$this->created_by_field] = (int) $this->authenticate->id();
1264 1264
         }
1265 1265
 
1266 1266
         return $row;
@@ -1332,7 +1332,7 @@  discard block
 block discarded – undo
1332 1332
      */
1333 1333
     public function trigger($event, $data = false)
1334 1334
     {
1335
-        if (! isset($this->$event) || ! is_array($this->$event))
1335
+        if ( ! isset($this->$event) || ! is_array($this->$event))
1336 1336
         {
1337 1337
             if (isset($data['fields']))
1338 1338
             {
@@ -1397,18 +1397,18 @@  discard block
 block discarded – undo
1397 1397
             $this->load->database();
1398 1398
         }
1399 1399
 
1400
-        if (!empty($this->validation_rules)) {
1400
+        if ( ! empty($this->validation_rules)) {
1401 1401
             $this->form_validation->set_data($data);
1402 1402
 
1403 1403
             if (is_array($this->validation_rules)) {
1404 1404
                 // Any insert additions?
1405 1405
                 if ($type == 'insert'
1406
-                    && !empty($this->insert_validate_rules)
1406
+                    && ! empty($this->insert_validate_rules)
1407 1407
                     && is_array($this->insert_validate_rules)
1408 1408
                 ) {
1409 1409
                     foreach ($this->validation_rules as &$row) {
1410 1410
                         if (isset($this->insert_validate_rules[$row['field']])) {
1411
-                            $row ['rules'] .= '|' . $this->insert_validate_rules[$row['field']];
1411
+                            $row ['rules'] .= '|'.$this->insert_validate_rules[$row['field']];
1412 1412
                         }
1413 1413
                     }
1414 1414
                 }
@@ -1475,7 +1475,7 @@  discard block
 block discarded – undo
1475 1475
      */
1476 1476
     protected function set_date($user_date = NULL)
1477 1477
     {
1478
-        $curr_date = !empty($user_date) ? $user_date : time();
1478
+        $curr_date = ! empty($user_date) ? $user_date : time();
1479 1479
 
1480 1480
         switch ($this->date_format) {
1481 1481
             case 'int':
@@ -1499,7 +1499,7 @@  discard block
 block discarded – undo
1499 1499
      *
1500 1500
      * @return mixed
1501 1501
      */
1502
-    public function error($db_array_only=false)
1502
+    public function error($db_array_only = false)
1503 1503
     {
1504 1504
         // Send any validation errors if we have any.
1505 1505
         if (function_exists('validation_errors') && validation_errors() && ! $db_array_only)
@@ -1515,7 +1515,7 @@  discard block
 block discarded – undo
1515 1515
             return $error;
1516 1516
         }
1517 1517
 
1518
-        if (! empty($error['code']))
1518
+        if ( ! empty($error['code']))
1519 1519
         {
1520 1520
             return "Database Error {$error['code']}: {$error['message']}.";
1521 1521
         }
Please login to merge, or discard this patch.