Completed
Branch 1.2 (459185)
by David
04:06
created
lib/Dwoo/Adapters/CodeIgniter/libraries/Dwootemplate.php 1 patch
Indentation   +149 added lines, -149 removed lines patch added patch discarded remove patch
@@ -20,153 +20,153 @@
 block discarded – undo
20 20
  * @uses the dwoo package from http://dwoo.org
21 21
  */
22 22
 class Dwootemplate extends Dwoo_Core {
23
-    protected $dwoo_data = array();
24
-
25
-    /**
26
-     * Constructor for the DwooTemplate engine
27
-     *
28
-     */
29
-    public function __construct() {
30
-        // Call parents constructor
31
-        parent::__construct();
32
-
33
-        // Set the config settings
34
-        $this->initialize();
35
-
36
-        // Assign some defaults to dwoo
37
-        $CI                         = get_instance();
38
-        $this->dwoo_data            = new Dwoo_Data();
39
-        $this->dwoo_data->js_files  = array();
40
-        $this->dwoo_data->css_files = array();
41
-        $this->dwoo_data->CI        = $CI;
42
-        $this->dwoo_data->site_url  = $CI->config->site_url(); // so we can get the full path to CI easily
43
-        $this->dwoo_data->uniqid    = uniqid();
44
-        $this->dwoo_data->timestamp = mktime();
45
-
46
-        log_message('debug', "Dwoo Template Class Initialized");
47
-    }
48
-
49
-
50
-    /**
51
-     * Assign data to dwoo data object
52
-     *
53
-     * @param string $key
54
-     * @param mixed $value
55
-     */
56
-    public function assign($key, $value) {
57
-        $this->dwoo_data->$key = $value;
58
-    }
59
-
60
-
61
-    /**
62
-     * Add Javascript files to template
63
-     *
64
-     * @param string $js
65
-     */
66
-    public function add_js($js) {
67
-        $current   = $this->dwoo_data->js_files;
68
-        $current[] = $js;
69
-        $this->dwoo_data->js_files = $current;
70
-    }
71
-
72
-
73
-    /**
74
-     * Add Css stylesheets to template
75
-     *
76
-     * @param string $css
77
-     */
78
-    public function add_css($css) {
79
-        $current   = $this->dwoo_data->css_files;
80
-        $current[] = $css;
81
-        $this->dwoo_data->css_files = $current;
82
-    }
83
-
84
-
85
-    /**
86
-     * Display or return the compiled template
87
-     * Since we assign the results to the standard CI output module
88
-     * you can also use the helper from CI in your templates!!
89
-     *
90
-     * @param string $sTemplate
91
-     * @param boolean $return
92
-     * @return mixed
93
-     */
94
-    public function display($sTemplate, $return = FALSE) {
95
-        // Start benchmark
96
-        $CI = get_instance();
97
-        $CI->benchmark->mark('dwoo_parse_start');
98
-
99
-        // Check if file exists
100
-        if ( !file_exists($this->template_dir . $sTemplate ) ) {
101
-            $message = sprintf('Template file \'%s\' not found.', $sTemplate);
102
-            show_error($message);
103
-            log_message('error', $message);
104
-        }
105
-
106
-        // Create new template
107
-        $tpl = new Dwoo_Template_File($this->template_dir . $sTemplate);
108
-
109
-        // render the template
110
-        $template = $this->get($tpl, $this->dwoo_data);
111
-
112
-        // Finish benchmark
113
-        $CI->benchmark->mark('dwoo_parse_end');
114
-
115
-        // Return results or not ?
116
-        if ($return == FALSE) {
117
-            $CI->output->final_output = $template;
118
-        } else {
119
-            return $template;
120
-        }
121
-    }
122
-
123
-
124
-    /**
125
-     * Toggle Codeigniter profiler on/off
126
-     *
127
-     */
128
-    public function enable_profiler($toggle = TRUE) {
129
-        $CI = get_instance();
130
-        $CI->output->enable_profiler($toggle);
131
-    }
132
-
133
-
134
-    /**
135
-     * Set http header
136
-     *
137
-     * @example $this->output->set_header("HTTP/1.1 200 OK");
138
-     * @example $this->output->set_header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_update).' GMT');
139
-     * @param string $header
140
-     */
141
-    public function set_header($header) {
142
-        $CI = get_instance();
143
-        $CI->output->set_header($header);
144
-    }
145
-
146
-
147
-    /**
148
-     * Set status header
149
-     *
150
-     * @example $this->output->set_status_header('401');
151
-     * @example // Sets the header as: Unauthorized
152
-     * @param string $header
153
-     */
154
-    public function set_status_header($header) {
155
-        $CI = get_instance();
156
-        $CI->output->set_status_header($header);
157
-    }
158
-
159
-
160
-    /**
161
-     * Assign the dwootemplate config items to the instance
162
-     *
163
-     */
164
-    private function initialize() {
165
-        $CI = get_instance();
166
-        $CI->config->load('dwootemplate', TRUE);
167
-        $config = $CI->config->item('dwootemplate');
168
-        foreach ($config as $key => $val) {
169
-                $this->$key = $val;
170
-        }
171
-    }
23
+	protected $dwoo_data = array();
24
+
25
+	/**
26
+	 * Constructor for the DwooTemplate engine
27
+	 *
28
+	 */
29
+	public function __construct() {
30
+		// Call parents constructor
31
+		parent::__construct();
32
+
33
+		// Set the config settings
34
+		$this->initialize();
35
+
36
+		// Assign some defaults to dwoo
37
+		$CI                         = get_instance();
38
+		$this->dwoo_data            = new Dwoo_Data();
39
+		$this->dwoo_data->js_files  = array();
40
+		$this->dwoo_data->css_files = array();
41
+		$this->dwoo_data->CI        = $CI;
42
+		$this->dwoo_data->site_url  = $CI->config->site_url(); // so we can get the full path to CI easily
43
+		$this->dwoo_data->uniqid    = uniqid();
44
+		$this->dwoo_data->timestamp = mktime();
45
+
46
+		log_message('debug', "Dwoo Template Class Initialized");
47
+	}
48
+
49
+
50
+	/**
51
+	 * Assign data to dwoo data object
52
+	 *
53
+	 * @param string $key
54
+	 * @param mixed $value
55
+	 */
56
+	public function assign($key, $value) {
57
+		$this->dwoo_data->$key = $value;
58
+	}
59
+
60
+
61
+	/**
62
+	 * Add Javascript files to template
63
+	 *
64
+	 * @param string $js
65
+	 */
66
+	public function add_js($js) {
67
+		$current   = $this->dwoo_data->js_files;
68
+		$current[] = $js;
69
+		$this->dwoo_data->js_files = $current;
70
+	}
71
+
72
+
73
+	/**
74
+	 * Add Css stylesheets to template
75
+	 *
76
+	 * @param string $css
77
+	 */
78
+	public function add_css($css) {
79
+		$current   = $this->dwoo_data->css_files;
80
+		$current[] = $css;
81
+		$this->dwoo_data->css_files = $current;
82
+	}
83
+
84
+
85
+	/**
86
+	 * Display or return the compiled template
87
+	 * Since we assign the results to the standard CI output module
88
+	 * you can also use the helper from CI in your templates!!
89
+	 *
90
+	 * @param string $sTemplate
91
+	 * @param boolean $return
92
+	 * @return mixed
93
+	 */
94
+	public function display($sTemplate, $return = FALSE) {
95
+		// Start benchmark
96
+		$CI = get_instance();
97
+		$CI->benchmark->mark('dwoo_parse_start');
98
+
99
+		// Check if file exists
100
+		if ( !file_exists($this->template_dir . $sTemplate ) ) {
101
+			$message = sprintf('Template file \'%s\' not found.', $sTemplate);
102
+			show_error($message);
103
+			log_message('error', $message);
104
+		}
105
+
106
+		// Create new template
107
+		$tpl = new Dwoo_Template_File($this->template_dir . $sTemplate);
108
+
109
+		// render the template
110
+		$template = $this->get($tpl, $this->dwoo_data);
111
+
112
+		// Finish benchmark
113
+		$CI->benchmark->mark('dwoo_parse_end');
114
+
115
+		// Return results or not ?
116
+		if ($return == FALSE) {
117
+			$CI->output->final_output = $template;
118
+		} else {
119
+			return $template;
120
+		}
121
+	}
122
+
123
+
124
+	/**
125
+	 * Toggle Codeigniter profiler on/off
126
+	 *
127
+	 */
128
+	public function enable_profiler($toggle = TRUE) {
129
+		$CI = get_instance();
130
+		$CI->output->enable_profiler($toggle);
131
+	}
132
+
133
+
134
+	/**
135
+	 * Set http header
136
+	 *
137
+	 * @example $this->output->set_header("HTTP/1.1 200 OK");
138
+	 * @example $this->output->set_header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_update).' GMT');
139
+	 * @param string $header
140
+	 */
141
+	public function set_header($header) {
142
+		$CI = get_instance();
143
+		$CI->output->set_header($header);
144
+	}
145
+
146
+
147
+	/**
148
+	 * Set status header
149
+	 *
150
+	 * @example $this->output->set_status_header('401');
151
+	 * @example // Sets the header as: Unauthorized
152
+	 * @param string $header
153
+	 */
154
+	public function set_status_header($header) {
155
+		$CI = get_instance();
156
+		$CI->output->set_status_header($header);
157
+	}
158
+
159
+
160
+	/**
161
+	 * Assign the dwootemplate config items to the instance
162
+	 *
163
+	 */
164
+	private function initialize() {
165
+		$CI = get_instance();
166
+		$CI->config->load('dwootemplate', TRUE);
167
+		$config = $CI->config->item('dwootemplate');
168
+		foreach ($config as $key => $val) {
169
+				$this->$key = $val;
170
+		}
171
+	}
172 172
 }
173 173
\ No newline at end of file
Please login to merge, or discard this patch.
lib/Dwoo/Adapters/CodeIgniter/controllers/dwoowelcome.php 1 patch
Indentation   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -2,15 +2,15 @@
 block discarded – undo
2 2
 
3 3
 class Dwoowelcome extends Controller {
4 4
 
5
-    function __construct()
6
-    {
7
-        parent::Controller();
8
-    }
5
+	function __construct()
6
+	{
7
+		parent::Controller();
8
+	}
9 9
 
10
-    function index()
11
-    {
12
-    	$this->load->library('Dwootemplate');
13
-    	$this->dwootemplate->assign('itshowlate', date('H:i:s'));
14
-    	$this->dwootemplate->display('dwoowelcome.tpl');
15
-    }
10
+	function index()
11
+	{
12
+		$this->load->library('Dwootemplate');
13
+		$this->dwootemplate->assign('itshowlate', date('H:i:s'));
14
+		$this->dwootemplate->display('dwoowelcome.tpl');
15
+	}
16 16
 }
17 17
\ No newline at end of file
Please login to merge, or discard this patch.
lib/Dwoo/Adapters/CakePHP/dwoo.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@
 block discarded – undo
64 64
 		$this->_sv_compile_id = $controller->name;
65 65
 
66 66
 		$this->_dwoo->sv_this = $this;
67
-        $this->_dwoo->setSecurityPolicy();
67
+		$this->_dwoo->setSecurityPolicy();
68 68
 
69 69
 		return;
70 70
 	}
Please login to merge, or discard this patch.
lib/plugins/builtin/functions/reverse.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -24,11 +24,11 @@
 block discarded – undo
24 24
 	} elseif(($charset=$dwoo->getCharset()) === 'iso-8859-1') {
25 25
 		return strrev((string) $value);
26 26
 	} else {
27
-	    $strlen = mb_strlen($value);
28
-	    $out = '';
29
-	    while ($strlen--) {
30
-	        $out .= mb_substr($value, $strlen, 1, $charset);
31
-	    }
27
+		$strlen = mb_strlen($value);
28
+		$out = '';
29
+		while ($strlen--) {
30
+			$out .= mb_substr($value, $strlen, 1, $charset);
31
+		}
32 32
 		return $out;
33 33
 	}
34 34
 }
Please login to merge, or discard this patch.
lib/plugins/builtin/functions/return.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -24,9 +24,9 @@
 block discarded – undo
24 24
  */
25 25
 function Dwoo_Plugin_return_compile(Dwoo_Compiler $compiler, array $rest = array())
26 26
 {
27
-    $out = array();
28
-    foreach ($rest as $var => $val) {
29
-        $out[] = '$this->setReturnValue('.var_export($var, true).', '.$val.')';
30
-    }
31
-    return '('.implode('.', $out).')';
27
+	$out = array();
28
+	foreach ($rest as $var => $val) {
29
+		$out[] = '$this->setReturnValue('.var_export($var, true).', '.$val.')';
30
+	}
31
+	return '('.implode('.', $out).')';
32 32
 }
33 33
\ No newline at end of file
Please login to merge, or discard this patch.
lib/Dwoo/Core.php 1 patch
Indentation   +1413 added lines, -1413 removed lines patch added patch discarded remove patch
@@ -33,23 +33,23 @@  discard block
 block discarded – undo
33 33
  */
34 34
 class Dwoo_Core
35 35
 {
36
-    /**
37
-     * current version number
38
-     *
39
-     * @var string
40
-     */
41
-    const VERSION = '1.2.3';
36
+	/**
37
+	 * current version number
38
+	 *
39
+	 * @var string
40
+	 */
41
+	const VERSION = '1.2.3';
42 42
 
43
-    /**
44
-     * unique number of this dwoo release
45
-     *
46
-     * this can be used by templates classes to check whether the compiled template
47
-     * has been compiled before this release or not, so that old templates are
48
-     * recompiled automatically when Dwoo is updated
49
-     */
50
-    const RELEASE_TAG = 17;
43
+	/**
44
+	 * unique number of this dwoo release
45
+	 *
46
+	 * this can be used by templates classes to check whether the compiled template
47
+	 * has been compiled before this release or not, so that old templates are
48
+	 * recompiled automatically when Dwoo is updated
49
+	 */
50
+	const RELEASE_TAG = 17;
51 51
 
52
-    /**#@+
52
+	/**#@+
53 53
      * constants that represents all plugin types
54 54
      *
55 55
      * these are bitwise-operation-safe values to allow multiple types
@@ -57,251 +57,251 @@  discard block
 block discarded – undo
57 57
      *
58 58
      * @var int
59 59
      */
60
-    const CLASS_PLUGIN = 1;
61
-    const FUNC_PLUGIN = 2;
62
-    const NATIVE_PLUGIN = 4;
63
-    const BLOCK_PLUGIN = 8;
64
-    const COMPILABLE_PLUGIN = 16;
65
-    const CUSTOM_PLUGIN = 32;
66
-    const SMARTY_MODIFIER = 64;
67
-    const SMARTY_BLOCK = 128;
68
-    const SMARTY_FUNCTION = 256;
69
-    const PROXY_PLUGIN = 512;
70
-    const TEMPLATE_PLUGIN = 1024;
71
-    /**#@-*/
72
-
73
-    /**
74
-     * character set of the template, used by string manipulation plugins
75
-     *
76
-     * it must be lowercase, but setCharset() will take care of that
77
-     *
78
-     * @see setCharset
79
-     * @see getCharset
80
-     * @var string
81
-     */
82
-    protected $charset = 'utf-8';
60
+	const CLASS_PLUGIN = 1;
61
+	const FUNC_PLUGIN = 2;
62
+	const NATIVE_PLUGIN = 4;
63
+	const BLOCK_PLUGIN = 8;
64
+	const COMPILABLE_PLUGIN = 16;
65
+	const CUSTOM_PLUGIN = 32;
66
+	const SMARTY_MODIFIER = 64;
67
+	const SMARTY_BLOCK = 128;
68
+	const SMARTY_FUNCTION = 256;
69
+	const PROXY_PLUGIN = 512;
70
+	const TEMPLATE_PLUGIN = 1024;
71
+	/**#@-*/
83 72
 
84
-    /**
85
-     * global variables that are accessible through $dwoo.* in the templates
86
-     *
87
-     * default values include:
88
-     *
89
-     * $dwoo.version - current version number
90
-     * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
91
-     * $dwoo.now - the current time
92
-     * $dwoo.template - the current template filename
93
-     * $dwoo.charset - the character set used by the template
94
-     *
95
-     * on top of that, foreach and other plugins can store special values in there,
96
-     * see their documentation for more details.
97
-     *
98
-     * @private
99
-     * @var array
100
-     */
101
-    public $globals;
73
+	/**
74
+	 * character set of the template, used by string manipulation plugins
75
+	 *
76
+	 * it must be lowercase, but setCharset() will take care of that
77
+	 *
78
+	 * @see setCharset
79
+	 * @see getCharset
80
+	 * @var string
81
+	 */
82
+	protected $charset = 'utf-8';
102 83
 
103
-    /**
104
-     * directory where the compiled templates are stored
105
-     *
106
-     * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
107
-     *
108
-     * @var string
109
-     */
110
-    protected $compileDir;
84
+	/**
85
+	 * global variables that are accessible through $dwoo.* in the templates
86
+	 *
87
+	 * default values include:
88
+	 *
89
+	 * $dwoo.version - current version number
90
+	 * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
91
+	 * $dwoo.now - the current time
92
+	 * $dwoo.template - the current template filename
93
+	 * $dwoo.charset - the character set used by the template
94
+	 *
95
+	 * on top of that, foreach and other plugins can store special values in there,
96
+	 * see their documentation for more details.
97
+	 *
98
+	 * @private
99
+	 * @var array
100
+	 */
101
+	public $globals;
111 102
 
112
-    /**
113
-     * directory where the cached templates are stored
114
-     *
115
-     * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
116
-     *
117
-     * @var string
118
-     */
119
-    protected $cacheDir;
103
+	/**
104
+	 * directory where the compiled templates are stored
105
+	 *
106
+	 * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
107
+	 *
108
+	 * @var string
109
+	 */
110
+	protected $compileDir;
120 111
 
121
-    /**
122
-     * defines how long (in seconds) the cached files must remain valid
123
-     *
124
-     * can be overriden on a per-template basis
125
-     *
126
-     * -1 = never delete
127
-     * 0 = disabled
128
-     * >0 = duration in seconds
129
-     *
130
-     * @var int
131
-     */
132
-    protected $cacheTime = 0;
112
+	/**
113
+	 * directory where the cached templates are stored
114
+	 *
115
+	 * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
116
+	 *
117
+	 * @var string
118
+	 */
119
+	protected $cacheDir;
133 120
 
134
-    /**
135
-     * security policy object
136
-     *
137
-     * @var Dwoo_Security_Policy
138
-     */
139
-    protected $securityPolicy = null;
121
+	/**
122
+	 * defines how long (in seconds) the cached files must remain valid
123
+	 *
124
+	 * can be overriden on a per-template basis
125
+	 *
126
+	 * -1 = never delete
127
+	 * 0 = disabled
128
+	 * >0 = duration in seconds
129
+	 *
130
+	 * @var int
131
+	 */
132
+	protected $cacheTime = 0;
140 133
 
141
-    /**
142
-     * stores the custom plugins callbacks
143
-     *
144
-     * @see addPlugin
145
-     * @see removePlugin
146
-     * @var array
147
-     */
148
-    protected $plugins = array();
134
+	/**
135
+	 * security policy object
136
+	 *
137
+	 * @var Dwoo_Security_Policy
138
+	 */
139
+	protected $securityPolicy = null;
149 140
 
150
-    /**
151
-     * stores the filter callbacks
152
-     *
153
-     * @see addFilter
154
-     * @see removeFilter
155
-     * @var array
156
-     */
157
-    protected $filters = array();
141
+	/**
142
+	 * stores the custom plugins callbacks
143
+	 *
144
+	 * @see addPlugin
145
+	 * @see removePlugin
146
+	 * @var array
147
+	 */
148
+	protected $plugins = array();
158 149
 
159
-    /**
160
-     * stores the resource types and associated
161
-     * classes / compiler classes
162
-     *
163
-     * @var array
164
-     */
165
-    protected $resources = array
166
-    (
167
-        'file'      =>  array
168
-        (
169
-            'class'     =>  'Dwoo_Template_File',
170
-            'compiler'  =>  null
171
-        ),
172
-        'string'    =>  array
173
-        (
174
-            'class'     =>  'Dwoo_Template_String',
175
-            'compiler'  =>  null
176
-        )
177
-    );
178
-
179
-    /**
180
-     * the dwoo loader object used to load plugins by this dwoo instance
181
-     *
182
-     * @var Dwoo_ILoader
183
-     */
184
-    protected $loader = null;
150
+	/**
151
+	 * stores the filter callbacks
152
+	 *
153
+	 * @see addFilter
154
+	 * @see removeFilter
155
+	 * @var array
156
+	 */
157
+	protected $filters = array();
185 158
 
186
-    /**
187
-     * currently rendered template, set to null when not-rendering
188
-     *
189
-     * @var Dwoo_ITemplate
190
-     */
191
-    protected $template = null;
159
+	/**
160
+	 * stores the resource types and associated
161
+	 * classes / compiler classes
162
+	 *
163
+	 * @var array
164
+	 */
165
+	protected $resources = array
166
+	(
167
+		'file'      =>  array
168
+		(
169
+			'class'     =>  'Dwoo_Template_File',
170
+			'compiler'  =>  null
171
+		),
172
+		'string'    =>  array
173
+		(
174
+			'class'     =>  'Dwoo_Template_String',
175
+			'compiler'  =>  null
176
+		)
177
+	);
192 178
 
193
-    /**
194
-     * stores the instances of the class plugins during template runtime
195
-     *
196
-     * @var array
197
-     */
198
-    protected $runtimePlugins;
179
+	/**
180
+	 * the dwoo loader object used to load plugins by this dwoo instance
181
+	 *
182
+	 * @var Dwoo_ILoader
183
+	 */
184
+	protected $loader = null;
199 185
 
200
-    /**
201
-     * stores the returned values during template runtime
202
-     *
203
-     * @var array
204
-     */
205
-    protected $returnData;
186
+	/**
187
+	 * currently rendered template, set to null when not-rendering
188
+	 *
189
+	 * @var Dwoo_ITemplate
190
+	 */
191
+	protected $template = null;
206 192
 
207
-    /**
208
-     * stores the data during template runtime
209
-     *
210
-     * @var array
211
-     * @private
212
-     */
213
-    public $data;
193
+	/**
194
+	 * stores the instances of the class plugins during template runtime
195
+	 *
196
+	 * @var array
197
+	 */
198
+	protected $runtimePlugins;
214 199
 
215
-    /**
216
-     * stores the current scope during template runtime
217
-     *
218
-     * this should ideally not be accessed directly from outside template code
219
-     *
220
-     * @var mixed
221
-     * @private
222
-     */
223
-    public $scope;
200
+	/**
201
+	 * stores the returned values during template runtime
202
+	 *
203
+	 * @var array
204
+	 */
205
+	protected $returnData;
224 206
 
225
-    /**
226
-     * stores the scope tree during template runtime
227
-     *
228
-     * @var array
229
-     */
230
-    protected $scopeTree;
207
+	/**
208
+	 * stores the data during template runtime
209
+	 *
210
+	 * @var array
211
+	 * @private
212
+	 */
213
+	public $data;
231 214
 
232
-    /**
233
-     * stores the block plugins stack during template runtime
234
-     *
235
-     * @var array
236
-     */
237
-    protected $stack;
215
+	/**
216
+	 * stores the current scope during template runtime
217
+	 *
218
+	 * this should ideally not be accessed directly from outside template code
219
+	 *
220
+	 * @var mixed
221
+	 * @private
222
+	 */
223
+	public $scope;
238 224
 
239
-    /**
240
-     * stores the current block plugin at the top of the stack during template runtime
241
-     *
242
-     * @var Dwoo_Block_Plugin
243
-     */
244
-    protected $curBlock;
225
+	/**
226
+	 * stores the scope tree during template runtime
227
+	 *
228
+	 * @var array
229
+	 */
230
+	protected $scopeTree;
245 231
 
246
-    /**
247
-     * stores the output buffer during template runtime
248
-     *
249
-     * @var string
250
-     */
251
-    protected $buffer;
232
+	/**
233
+	 * stores the block plugins stack during template runtime
234
+	 *
235
+	 * @var array
236
+	 */
237
+	protected $stack;
252 238
 
253
-    /**
254
-     * stores plugin proxy
255
-     *
256
-     * @var Dwoo_IPluginProxy
257
-     */
258
-    protected $pluginProxy;
239
+	/**
240
+	 * stores the current block plugin at the top of the stack during template runtime
241
+	 *
242
+	 * @var Dwoo_Block_Plugin
243
+	 */
244
+	protected $curBlock;
259 245
 
260
-    /**
261
-     * constructor, sets the cache and compile dir to the default values if not provided
262
-     *
263
-     * @param string $compileDir path to the compiled directory, defaults to lib/compiled
264
-     * @param string $cacheDir path to the cache directory, defaults to lib/cache
265
-     */
266
-    public function __construct($compileDir = null, $cacheDir = null)
267
-    {
268
-        if ($compileDir !== null) {
269
-            $this->setCompileDir($compileDir);
270
-        }
271
-        if ($cacheDir !== null) {
272
-            $this->setCacheDir($cacheDir);
273
-        }
274
-        $this->initGlobals();
275
-    }
276
-
277
-    /**
278
-     * resets some runtime variables to allow a cloned object to be used to render sub-templates
279
-     */
280
-    public function __clone()
281
-    {
282
-        $this->template = null;
283
-        unset($this->data);
284
-        unset($this->returnData);
285
-    }
286
-
287
-    /**
288
-     * outputs the template instead of returning it, this is basically a shortcut for get(*, *, *, true)
289
-     *
290
-     * @see get
291
-     * @param mixed $tpl template, can either be a Dwoo_ITemplate object (i.e. Dwoo_Template_File), a valid path to a template, or
292
-     *                   a template as a string it is recommended to provide a Dwoo_ITemplate as it will probably make things faster,
293
-     *                   especially if you render a template multiple times
294
-     * @param mixed $data the data to use, can either be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array. if you're
295
-     *                    rendering the template from cache, it can be left null
296
-     * @param Dwoo_ICompiler $compiler the compiler that must be used to compile the template, if left empty a default
297
-     *                                Dwoo_Compiler will be used.
298
-     * @return string nothing or the template output if $output is true
246
+	/**
247
+	 * stores the output buffer during template runtime
248
+	 *
249
+	 * @var string
250
+	 */
251
+	protected $buffer;
252
+
253
+	/**
254
+	 * stores plugin proxy
255
+	 *
256
+	 * @var Dwoo_IPluginProxy
257
+	 */
258
+	protected $pluginProxy;
259
+
260
+	/**
261
+	 * constructor, sets the cache and compile dir to the default values if not provided
262
+	 *
263
+	 * @param string $compileDir path to the compiled directory, defaults to lib/compiled
264
+	 * @param string $cacheDir path to the cache directory, defaults to lib/cache
265
+	 */
266
+	public function __construct($compileDir = null, $cacheDir = null)
267
+	{
268
+		if ($compileDir !== null) {
269
+			$this->setCompileDir($compileDir);
270
+		}
271
+		if ($cacheDir !== null) {
272
+			$this->setCacheDir($cacheDir);
273
+		}
274
+		$this->initGlobals();
275
+	}
276
+
277
+	/**
278
+	 * resets some runtime variables to allow a cloned object to be used to render sub-templates
279
+	 */
280
+	public function __clone()
281
+	{
282
+		$this->template = null;
283
+		unset($this->data);
284
+		unset($this->returnData);
285
+	}
286
+
287
+	/**
288
+	 * outputs the template instead of returning it, this is basically a shortcut for get(*, *, *, true)
289
+	 *
290
+	 * @see get
291
+	 * @param mixed $tpl template, can either be a Dwoo_ITemplate object (i.e. Dwoo_Template_File), a valid path to a template, or
292
+	 *                   a template as a string it is recommended to provide a Dwoo_ITemplate as it will probably make things faster,
293
+	 *                   especially if you render a template multiple times
294
+	 * @param mixed $data the data to use, can either be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array. if you're
295
+	 *                    rendering the template from cache, it can be left null
296
+	 * @param Dwoo_ICompiler $compiler the compiler that must be used to compile the template, if left empty a default
297
+	 *                                Dwoo_Compiler will be used.
298
+	 * @return string nothing or the template output if $output is true
299 299
 	 * @deprecated 1.2.3. will be deleted in 1.3.0.
300
-     */
301
-    public function output($tpl, $data = array(), Dwoo_ICompiler $compiler = null)
302
-    {
303
-        return $this->get($tpl, $data, $compiler, true);
304
-    }
300
+	 */
301
+	public function output($tpl, $data = array(), Dwoo_ICompiler $compiler = null)
302
+	{
303
+		return $this->get($tpl, $data, $compiler, true);
304
+	}
305 305
 
306 306
 	/**
307 307
 	 * returns the given template rendered using the provided data and optional compiler
@@ -316,156 +316,156 @@  discard block
 block discarded – undo
316 316
 	 *                                Dwoo_Compiler will be used.
317 317
 	 * @param bool $_output flag that defines whether the function returns the output of the template (false, default) or echoes it directly (true)
318 318
 	 */
319
-    public function get($_tpl, $data = array(), $_compiler = null, $_output = false)
320
-    {
321
-        // a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
322
-        if ($this->template instanceof Dwoo_ITemplate) {
323
-            $clone = clone $this;
324
-            return $clone->get($_tpl, $data, $_compiler, $_output);
325
-        }
326
-
327
-        // auto-create template if required
328
-        if ($_tpl instanceof Dwoo_ITemplate) {
329
-            // valid, skip
330
-        } elseif (is_string($_tpl) && file_exists($_tpl)) {
331
-            $_tpl = new Dwoo_Template_File($_tpl);
332
-        } else {
333
-            throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s first argument must be a Dwoo_ITemplate (i.e. Dwoo_Template_File) or a valid path to a template file', E_USER_NOTICE);
334
-        }
335
-
336
-        // save the current template, enters render mode at the same time
337
-        // if another rendering is requested it will be proxied to a new Dwoo_Core(instance
338
-        $this->template = $_tpl;
339
-
340
-        // load data
341
-        if ($data instanceof Dwoo_IDataProvider) {
342
-            $this->data = $data->getData();
343
-        } elseif (is_array($data)) {
344
-            $this->data = $data;
345
-        } elseif ($data instanceof ArrayAccess) {
346
-            $this->data = $data;
347
-        } else {
348
-            throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s data argument must be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array', E_USER_NOTICE);
349
-        }
350
-
351
-        $this->globals['template'] = $_tpl->getName();
352
-        $this->initRuntimeVars($_tpl);
353
-
354
-        // try to get cached template
355
-        $file = $_tpl->getCachedTemplate($this);
356
-        $doCache = $file === true;
357
-        $cacheLoaded = is_string($file);
358
-
359
-        if ($cacheLoaded === true) {
360
-            // cache is present, run it
361
-            if ($_output === true) {
362
-                include $file;
363
-                $this->template = null;
364
-            } else {
365
-                ob_start();
366
-                include $file;
367
-                $this->template = null;
368
-                return ob_get_clean();
369
-            }
370
-        } else {
319
+	public function get($_tpl, $data = array(), $_compiler = null, $_output = false)
320
+	{
321
+		// a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
322
+		if ($this->template instanceof Dwoo_ITemplate) {
323
+			$clone = clone $this;
324
+			return $clone->get($_tpl, $data, $_compiler, $_output);
325
+		}
326
+
327
+		// auto-create template if required
328
+		if ($_tpl instanceof Dwoo_ITemplate) {
329
+			// valid, skip
330
+		} elseif (is_string($_tpl) && file_exists($_tpl)) {
331
+			$_tpl = new Dwoo_Template_File($_tpl);
332
+		} else {
333
+			throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s first argument must be a Dwoo_ITemplate (i.e. Dwoo_Template_File) or a valid path to a template file', E_USER_NOTICE);
334
+		}
335
+
336
+		// save the current template, enters render mode at the same time
337
+		// if another rendering is requested it will be proxied to a new Dwoo_Core(instance
338
+		$this->template = $_tpl;
339
+
340
+		// load data
341
+		if ($data instanceof Dwoo_IDataProvider) {
342
+			$this->data = $data->getData();
343
+		} elseif (is_array($data)) {
344
+			$this->data = $data;
345
+		} elseif ($data instanceof ArrayAccess) {
346
+			$this->data = $data;
347
+		} else {
348
+			throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s data argument must be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array', E_USER_NOTICE);
349
+		}
350
+
351
+		$this->globals['template'] = $_tpl->getName();
352
+		$this->initRuntimeVars($_tpl);
353
+
354
+		// try to get cached template
355
+		$file = $_tpl->getCachedTemplate($this);
356
+		$doCache = $file === true;
357
+		$cacheLoaded = is_string($file);
358
+
359
+		if ($cacheLoaded === true) {
360
+			// cache is present, run it
361
+			if ($_output === true) {
362
+				include $file;
363
+				$this->template = null;
364
+			} else {
365
+				ob_start();
366
+				include $file;
367
+				$this->template = null;
368
+				return ob_get_clean();
369
+			}
370
+		} else {
371 371
 			$dynamicId = uniqid();
372 372
 
373
-            // render template
374
-            $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
375
-            $out = include $compiledTemplate;
376
-
377
-            // template returned false so it needs to be recompiled
378
-            if ($out === false) {
379
-                $_tpl->forceCompilation();
380
-                $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
381
-                $out = include $compiledTemplate;
382
-            }
383
-
384
-            if ($doCache === true) {
385
-
386
-                $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*'.$dynamicId.'*/ echo \'$1\'; ?>', $out);
387
-                if (!class_exists('Dwoo_plugin_dynamic')) {
388
-                    $this->getLoader()->loadPlugin('dynamic');
389
-                }
390
-                $out = Dwoo_Plugin_dynamic::unescape($out, $dynamicId, $compiledTemplate);
391
-            }
392
-
393
-            // process filters
394
-            foreach ($this->filters as $filter) {
395
-                if (is_array($filter) && $filter[0] instanceof Dwoo_Filter) {
396
-                    $out = call_user_func($filter, $out);
397
-                } else {
398
-                    $out = call_user_func($filter, $this, $out);
399
-                }
400
-            }
401
-
402
-            if ($doCache === true) {
403
-                // building cache
404
-                $file = $_tpl->cache($this, $out);
405
-
406
-                // run it from the cache to be sure dynamics are rendered
407
-                if ($_output === true) {
408
-                    include $file;
409
-                    // exit render mode
410
-                    $this->template = null;
411
-                } else {
412
-                    ob_start();
413
-                    include $file;
414
-                    // exit render mode
415
-                    $this->template = null;
416
-                    return ob_get_clean();
417
-                }
418
-            } else {
419
-                // no need to build cache
420
-                // exit render mode
421
-                $this->template = null;
422
-                // output
423
-                if ($_output === true) {
424
-                    echo $out;
425
-                }
426
-                return $out;
427
-            }
428
-        }
429
-
430
-        return '';
431
-    }
432
-
433
-    /**
434
-     * re-initializes the globals array before each template run
435
-     *
436
-     * this method is only callede once when the Dwoo object is created
437
-     */
438
-    protected function initGlobals()
439
-    {
440
-        $this->globals = array
441
-        (
442
-            'version'   =>  self::VERSION,
443
-            'ad'        =>  '<a href="http://dwoo.org/">Powered by Dwoo</a>',
444
-            'now'       =>  $_SERVER['REQUEST_TIME'],
445
-            'charset'   =>  $this->charset,
446
-        );
447
-    }
448
-
449
-    /**
450
-     * re-initializes the runtime variables before each template run
451
-     *
452
-     * override this method to inject data in the globals array if needed, this
453
-     * method is called before each template execution
454
-     *
455
-     * @param Dwoo_ITemplate $tpl the template that is going to be rendered
456
-     */
457
-    protected function initRuntimeVars(Dwoo_ITemplate $tpl)
458
-    {
459
-        $this->runtimePlugins = array();
460
-        $this->scope =& $this->data;
461
-        $this->scopeTree = array();
462
-        $this->stack = array();
463
-        $this->curBlock = null;
464
-        $this->buffer = '';
465
-        $this->returnData = array();
466
-    }
467
-
468
-    /*
373
+			// render template
374
+			$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
375
+			$out = include $compiledTemplate;
376
+
377
+			// template returned false so it needs to be recompiled
378
+			if ($out === false) {
379
+				$_tpl->forceCompilation();
380
+				$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
381
+				$out = include $compiledTemplate;
382
+			}
383
+
384
+			if ($doCache === true) {
385
+
386
+				$out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*'.$dynamicId.'*/ echo \'$1\'; ?>', $out);
387
+				if (!class_exists('Dwoo_plugin_dynamic')) {
388
+					$this->getLoader()->loadPlugin('dynamic');
389
+				}
390
+				$out = Dwoo_Plugin_dynamic::unescape($out, $dynamicId, $compiledTemplate);
391
+			}
392
+
393
+			// process filters
394
+			foreach ($this->filters as $filter) {
395
+				if (is_array($filter) && $filter[0] instanceof Dwoo_Filter) {
396
+					$out = call_user_func($filter, $out);
397
+				} else {
398
+					$out = call_user_func($filter, $this, $out);
399
+				}
400
+			}
401
+
402
+			if ($doCache === true) {
403
+				// building cache
404
+				$file = $_tpl->cache($this, $out);
405
+
406
+				// run it from the cache to be sure dynamics are rendered
407
+				if ($_output === true) {
408
+					include $file;
409
+					// exit render mode
410
+					$this->template = null;
411
+				} else {
412
+					ob_start();
413
+					include $file;
414
+					// exit render mode
415
+					$this->template = null;
416
+					return ob_get_clean();
417
+				}
418
+			} else {
419
+				// no need to build cache
420
+				// exit render mode
421
+				$this->template = null;
422
+				// output
423
+				if ($_output === true) {
424
+					echo $out;
425
+				}
426
+				return $out;
427
+			}
428
+		}
429
+
430
+		return '';
431
+	}
432
+
433
+	/**
434
+	 * re-initializes the globals array before each template run
435
+	 *
436
+	 * this method is only callede once when the Dwoo object is created
437
+	 */
438
+	protected function initGlobals()
439
+	{
440
+		$this->globals = array
441
+		(
442
+			'version'   =>  self::VERSION,
443
+			'ad'        =>  '<a href="http://dwoo.org/">Powered by Dwoo</a>',
444
+			'now'       =>  $_SERVER['REQUEST_TIME'],
445
+			'charset'   =>  $this->charset,
446
+		);
447
+	}
448
+
449
+	/**
450
+	 * re-initializes the runtime variables before each template run
451
+	 *
452
+	 * override this method to inject data in the globals array if needed, this
453
+	 * method is called before each template execution
454
+	 *
455
+	 * @param Dwoo_ITemplate $tpl the template that is going to be rendered
456
+	 */
457
+	protected function initRuntimeVars(Dwoo_ITemplate $tpl)
458
+	{
459
+		$this->runtimePlugins = array();
460
+		$this->scope =& $this->data;
461
+		$this->scopeTree = array();
462
+		$this->stack = array();
463
+		$this->curBlock = null;
464
+		$this->buffer = '';
465
+		$this->returnData = array();
466
+	}
467
+
468
+	/*
469 469
      * --------- settings functions ---------
470 470
      */
471 471
 
@@ -478,16 +478,16 @@  discard block
 block discarded – undo
478 478
 	 * @param bool     $compilable if set to true, the plugin is assumed to be compilable
479 479
 	 * @throws Dwoo_Exception
480 480
 	 */
481
-    public function addPlugin($name, $callback, $compilable = false)
482
-    {
483
-        $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
484
-        if (is_array($callback)) {
485
-            if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo_Block_Plugin')) {
486
-                $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]));
487
-            } else {
488
-                $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]), 'function'=>$callback[1]);
489
-            }
490
-        } elseif(is_string($callback)) {
481
+	public function addPlugin($name, $callback, $compilable = false)
482
+	{
483
+		$compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
484
+		if (is_array($callback)) {
485
+			if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo_Block_Plugin')) {
486
+				$this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]));
487
+			} else {
488
+				$this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]), 'function'=>$callback[1]);
489
+			}
490
+		} elseif(is_string($callback)) {
491 491
 			if (class_exists($callback)) {
492 492
 				if (is_subclass_of($callback, 'Dwoo_Block_Plugin')) {
493 493
 					$this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback);
@@ -502,21 +502,21 @@  discard block
 block discarded – undo
502 502
 		} elseif($callback instanceof \Closure) {
503 503
 			$this->plugins[$name] = array('type'=>self::FUNC_PLUGIN | $compilable, 'callback'=>$callback);
504 504
 		} else {
505
-            throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists');
506
-        }
507
-    }
505
+			throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists');
506
+		}
507
+	}
508 508
 
509
-    /**
510
-     * removes a custom plugin
511
-     *
512
-     * @param string $name the plugin name
513
-     */
514
-    public function removePlugin($name)
515
-    {
516
-        if (isset($this->plugins[$name])) {
517
-            unset($this->plugins[$name]);
518
-        }
519
-    }
509
+	/**
510
+	 * removes a custom plugin
511
+	 *
512
+	 * @param string $name the plugin name
513
+	 */
514
+	public function removePlugin($name)
515
+	{
516
+		if (isset($this->plugins[$name])) {
517
+			unset($this->plugins[$name]);
518
+		}
519
+	}
520 520
 
521 521
 	/**
522 522
 	 * adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this instance
@@ -524,58 +524,58 @@  discard block
 block discarded – undo
524 524
 	 * @param bool  $autoload if true, the first parameter must be a filter name from one of the plugin directories
525 525
 	 * @throws Dwoo_Exception
526 526
 	 */
527
-    public function addFilter($callback, $autoload = false)
528
-    {
529
-        if ($autoload) {
530
-            $class = 'Dwoo_Filter_'.$callback;
531
-
532
-            if (!class_exists($class) && !function_exists($class)) {
533
-                try {
534
-                    $this->getLoader()->loadPlugin($callback);
535
-                } catch (Dwoo_Exception $e) {
536
-                    if (strstr($callback, 'Dwoo_Filter_')) {
537
-                        throw new Dwoo_Exception('Wrong filter name : '.$callback.', the "Dwoo_Filter_" prefix should not be used, please only use "'.str_replace('Dwoo_Filter_', '', $callback).'"');
538
-                    } else {
539
-                        throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"');
540
-                    }
541
-                }
542
-            }
543
-
544
-            if (class_exists($class)) {
545
-                $callback = array(new $class($this), 'process');
546
-            } elseif (function_exists($class)) {
547
-                $callback = $class;
548
-            } else {
549
-                throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"');
550
-            }
551
-
552
-            $this->filters[] = $callback;
553
-        } else {
554
-            $this->filters[] = $callback;
555
-        }
556
-    }
557
-
558
-    /**
559
-     * removes a filter
560
-     *
561
-     * @param mixed $callback callback or filter name if it was autoloaded
562
-     */
563
-    public function removeFilter($callback)
564
-    {
565
-        if (($index = array_search('Dwoo_Filter_'.$callback, $this->filters, true)) !== false) {
566
-            unset($this->filters[$index]);
567
-        } elseif (($index = array_search($callback, $this->filters, true)) !== false) {
568
-            unset($this->filters[$index]);
569
-        } else  {
570
-            $class = 'Dwoo_Filter_' . $callback;
571
-            foreach ($this->filters as $index=>$filter) {
572
-                if (is_array($filter) && $filter[0] instanceof $class) {
573
-                    unset($this->filters[$index]);
574
-                    break;
575
-                }
576
-            }
577
-        }
578
-    }
527
+	public function addFilter($callback, $autoload = false)
528
+	{
529
+		if ($autoload) {
530
+			$class = 'Dwoo_Filter_'.$callback;
531
+
532
+			if (!class_exists($class) && !function_exists($class)) {
533
+				try {
534
+					$this->getLoader()->loadPlugin($callback);
535
+				} catch (Dwoo_Exception $e) {
536
+					if (strstr($callback, 'Dwoo_Filter_')) {
537
+						throw new Dwoo_Exception('Wrong filter name : '.$callback.', the "Dwoo_Filter_" prefix should not be used, please only use "'.str_replace('Dwoo_Filter_', '', $callback).'"');
538
+					} else {
539
+						throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"');
540
+					}
541
+				}
542
+			}
543
+
544
+			if (class_exists($class)) {
545
+				$callback = array(new $class($this), 'process');
546
+			} elseif (function_exists($class)) {
547
+				$callback = $class;
548
+			} else {
549
+				throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"');
550
+			}
551
+
552
+			$this->filters[] = $callback;
553
+		} else {
554
+			$this->filters[] = $callback;
555
+		}
556
+	}
557
+
558
+	/**
559
+	 * removes a filter
560
+	 *
561
+	 * @param mixed $callback callback or filter name if it was autoloaded
562
+	 */
563
+	public function removeFilter($callback)
564
+	{
565
+		if (($index = array_search('Dwoo_Filter_'.$callback, $this->filters, true)) !== false) {
566
+			unset($this->filters[$index]);
567
+		} elseif (($index = array_search($callback, $this->filters, true)) !== false) {
568
+			unset($this->filters[$index]);
569
+		} else  {
570
+			$class = 'Dwoo_Filter_' . $callback;
571
+			foreach ($this->filters as $index=>$filter) {
572
+				if (is_array($filter) && $filter[0] instanceof $class) {
573
+					unset($this->filters[$index]);
574
+					break;
575
+				}
576
+			}
577
+		}
578
+	}
579 579
 
580 580
 	/**
581 581
 	 * adds a resource or overrides a default one
@@ -584,274 +584,274 @@  discard block
 block discarded – undo
584 584
 	 * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance used to compile this resource, if none is provided. by default it will produce a Dwoo_Compiler object
585 585
 	 * @throws Dwoo_Exception
586 586
 	 */
587
-    public function addResource($name, $class, $compilerFactory = null)
588
-    {
589
-        if (strlen($name) < 2) {
590
-            throw new Dwoo_Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
591
-        }
587
+	public function addResource($name, $class, $compilerFactory = null)
588
+	{
589
+		if (strlen($name) < 2) {
590
+			throw new Dwoo_Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
591
+		}
592 592
 
593
-        if (!class_exists($class)) {
594
-            throw new Dwoo_Exception('Resource class does not exist');
595
-        }
593
+		if (!class_exists($class)) {
594
+			throw new Dwoo_Exception('Resource class does not exist');
595
+		}
596 596
 
597
-        $interfaces = class_implements($class);
598
-        if (in_array('Dwoo_ITemplate', $interfaces) === false) {
599
-            throw new Dwoo_Exception('Resource class must implement Dwoo_ITemplate');
600
-        }
597
+		$interfaces = class_implements($class);
598
+		if (in_array('Dwoo_ITemplate', $interfaces) === false) {
599
+			throw new Dwoo_Exception('Resource class must implement Dwoo_ITemplate');
600
+		}
601 601
 
602
-        $this->resources[$name] = array('class'=>$class, 'compiler'=>$compilerFactory);
603
-    }
602
+		$this->resources[$name] = array('class'=>$class, 'compiler'=>$compilerFactory);
603
+	}
604 604
 
605
-    /**
606
-     * removes a custom resource
607
-     *
608
-     * @param string $name the resource name
609
-     */
610
-    public function removeResource($name)
611
-    {
612
-        unset($this->resources[$name]);
613
-        if ($name==='file') {
614
-            $this->resources['file'] = array('class'=>'Dwoo_Template_File', 'compiler'=>null);
615
-        }
616
-    }
617
-
618
-    /*
605
+	/**
606
+	 * removes a custom resource
607
+	 *
608
+	 * @param string $name the resource name
609
+	 */
610
+	public function removeResource($name)
611
+	{
612
+		unset($this->resources[$name]);
613
+		if ($name==='file') {
614
+			$this->resources['file'] = array('class'=>'Dwoo_Template_File', 'compiler'=>null);
615
+		}
616
+	}
617
+
618
+	/*
619 619
      * --------- getters and setters ---------
620 620
      */
621 621
 
622
-    /**
623
-     * sets the loader object to use to load plugins
624
-     *
625
-     * @param Dwoo_ILoader $loader loader object
626
-     */
627
-    public function setLoader(Dwoo_ILoader $loader)
628
-    {
629
-        $this->loader = $loader;
630
-    }
622
+	/**
623
+	 * sets the loader object to use to load plugins
624
+	 *
625
+	 * @param Dwoo_ILoader $loader loader object
626
+	 */
627
+	public function setLoader(Dwoo_ILoader $loader)
628
+	{
629
+		$this->loader = $loader;
630
+	}
631 631
 
632 632
 	/**
633 633
 	 * returns the current loader object or a default one if none is currently found
634 634
 	 * @param Dwoo_ILoader
635 635
 	 * @return Dwoo_ILoader|Dwoo_Loader
636 636
 	 */
637
-    public function getLoader()
638
-    {
639
-        if ($this->loader === null) {
640
-            $this->loader = new Dwoo_Loader($this->getCompileDir());
641
-        }
637
+	public function getLoader()
638
+	{
639
+		if ($this->loader === null) {
640
+			$this->loader = new Dwoo_Loader($this->getCompileDir());
641
+		}
642 642
 
643
-        return $this->loader;
644
-    }
643
+		return $this->loader;
644
+	}
645 645
 
646
-    /**
647
-     * returns the custom plugins loaded
648
-     *
649
-     * used by the Dwoo_ITemplate classes to pass the custom plugins to their Dwoo_ICompiler instance
650
-     *
651
-     * @return array
652
-     */
653
-    public function getCustomPlugins()
654
-    {
655
-        return $this->plugins;
656
-    }
646
+	/**
647
+	 * returns the custom plugins loaded
648
+	 *
649
+	 * used by the Dwoo_ITemplate classes to pass the custom plugins to their Dwoo_ICompiler instance
650
+	 *
651
+	 * @return array
652
+	 */
653
+	public function getCustomPlugins()
654
+	{
655
+		return $this->plugins;
656
+	}
657 657
 
658
-    /**
659
-     * returns the cache directory with a trailing DIRECTORY_SEPARATOR
660
-     *
661
-     * @return string
662
-     */
663
-    public function getCacheDir()
664
-    {
665
-        if ($this->cacheDir === null) {
666
-            $this->setCacheDir(DWOO_DIRECTORY.'cache'.DIRECTORY_SEPARATOR);
667
-        }
658
+	/**
659
+	 * returns the cache directory with a trailing DIRECTORY_SEPARATOR
660
+	 *
661
+	 * @return string
662
+	 */
663
+	public function getCacheDir()
664
+	{
665
+		if ($this->cacheDir === null) {
666
+			$this->setCacheDir(DWOO_DIRECTORY.'cache'.DIRECTORY_SEPARATOR);
667
+		}
668 668
 
669
-        return $this->cacheDir;
670
-    }
669
+		return $this->cacheDir;
670
+	}
671 671
 
672 672
 	/**
673 673
 	 * sets the cache directory and automatically appends a DIRECTORY_SEPARATOR
674 674
 	 * @param string $dir the cache directory
675 675
 	 * @throws Dwoo_Exception
676 676
 	 */
677
-    public function setCacheDir($dir)
678
-    {
679
-        $this->cacheDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR;
680
-        if (is_writable($this->cacheDir) === false) {
681
-            throw new Dwoo_Exception('The cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable');
682
-        }
683
-    }
677
+	public function setCacheDir($dir)
678
+	{
679
+		$this->cacheDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR;
680
+		if (is_writable($this->cacheDir) === false) {
681
+			throw new Dwoo_Exception('The cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable');
682
+		}
683
+	}
684 684
 
685
-    /**
686
-     * returns the compile directory with a trailing DIRECTORY_SEPARATOR
687
-     *
688
-     * @return string
689
-     */
690
-    public function getCompileDir()
691
-    {
692
-        if ($this->compileDir === null) {
693
-            $this->setCompileDir(DWOO_DIRECTORY.'compiled'.DIRECTORY_SEPARATOR);
694
-        }
685
+	/**
686
+	 * returns the compile directory with a trailing DIRECTORY_SEPARATOR
687
+	 *
688
+	 * @return string
689
+	 */
690
+	public function getCompileDir()
691
+	{
692
+		if ($this->compileDir === null) {
693
+			$this->setCompileDir(DWOO_DIRECTORY.'compiled'.DIRECTORY_SEPARATOR);
694
+		}
695 695
 
696
-        return $this->compileDir;
697
-    }
696
+		return $this->compileDir;
697
+	}
698 698
 
699 699
 	/**
700 700
 	 * sets the compile directory and automatically appends a DIRECTORY_SEPARATOR
701 701
 	 * @param string $dir the compile directory
702 702
 	 * @throws Dwoo_Exception
703 703
 	 */
704
-    public function setCompileDir($dir)
705
-    {
706
-        $this->compileDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR;
707
-        if (is_writable($this->compileDir) === false) {
708
-            throw new Dwoo_Exception('The compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable');
709
-        }
710
-    }
711
-
712
-    /**
713
-     * returns the default cache time that is used with templates that do not have a cache time set
714
-     *
715
-     * @return int the duration in seconds
716
-     */
717
-    public function getCacheTime()
718
-    {
719
-        return $this->cacheTime;
720
-    }
704
+	public function setCompileDir($dir)
705
+	{
706
+		$this->compileDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR;
707
+		if (is_writable($this->compileDir) === false) {
708
+			throw new Dwoo_Exception('The compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable');
709
+		}
710
+	}
721 711
 
722
-    /**
723
-     * sets the default cache time to use with templates that do not have a cache time set
724
-     *
725
-     * @param int $seconds the duration in seconds
726
-     */
727
-    public function setCacheTime($seconds)
728
-    {
729
-        $this->cacheTime = (int) $seconds;
730
-    }
712
+	/**
713
+	 * returns the default cache time that is used with templates that do not have a cache time set
714
+	 *
715
+	 * @return int the duration in seconds
716
+	 */
717
+	public function getCacheTime()
718
+	{
719
+		return $this->cacheTime;
720
+	}
731 721
 
732
-    /**
733
-     * returns the character set used by the string manipulation plugins
734
-     *
735
-     * the charset is automatically lowercased
736
-     *
737
-     * @return string
738
-     */
739
-    public function getCharset()
740
-    {
741
-        return $this->charset;
742
-    }
722
+	/**
723
+	 * sets the default cache time to use with templates that do not have a cache time set
724
+	 *
725
+	 * @param int $seconds the duration in seconds
726
+	 */
727
+	public function setCacheTime($seconds)
728
+	{
729
+		$this->cacheTime = (int) $seconds;
730
+	}
743 731
 
744
-    /**
745
-     * sets the character set used by the string manipulation plugins
746
-     *
747
-     * the charset will be automatically lowercased
748
-     *
749
-     * @param string $charset the character set
750
-     */
751
-    public function setCharset($charset)
752
-    {
753
-        $this->charset = strtolower((string) $charset);
754
-    }
732
+	/**
733
+	 * returns the character set used by the string manipulation plugins
734
+	 *
735
+	 * the charset is automatically lowercased
736
+	 *
737
+	 * @return string
738
+	 */
739
+	public function getCharset()
740
+	{
741
+		return $this->charset;
742
+	}
755 743
 
756
-    /**
757
-     * returns the current template being rendered, when applicable, or null
758
-     *
759
-     * @return Dwoo_ITemplate|null
760
-     */
761
-    public function getTemplate()
762
-    {
763
-        return $this->template;
764
-    }
744
+	/**
745
+	 * sets the character set used by the string manipulation plugins
746
+	 *
747
+	 * the charset will be automatically lowercased
748
+	 *
749
+	 * @param string $charset the character set
750
+	 */
751
+	public function setCharset($charset)
752
+	{
753
+		$this->charset = strtolower((string) $charset);
754
+	}
765 755
 
766
-    /**
767
-     * sets the current template being rendered
768
-     *
769
-     * @param Dwoo_ITemplate $tpl template object
770
-     */
771
-    public function setTemplate(Dwoo_ITemplate $tpl)
772
-    {
773
-        $this->template = $tpl;
774
-    }
756
+	/**
757
+	 * returns the current template being rendered, when applicable, or null
758
+	 *
759
+	 * @return Dwoo_ITemplate|null
760
+	 */
761
+	public function getTemplate()
762
+	{
763
+		return $this->template;
764
+	}
775 765
 
776
-    /**
777
-     * sets the default compiler factory function for the given resource name
778
-     *
779
-     * a compiler factory must return a Dwoo_ICompiler object pre-configured to fit your needs
780
-     *
781
-     * @param string $resourceName the resource name (i.e. file, string)
782
-     * @param callback $compilerFactory the compiler factory callback
783
-     */
784
-    public function setDefaultCompilerFactory($resourceName, $compilerFactory)
785
-    {
786
-        $this->resources[$resourceName]['compiler'] = $compilerFactory;
787
-    }
766
+	/**
767
+	 * sets the current template being rendered
768
+	 *
769
+	 * @param Dwoo_ITemplate $tpl template object
770
+	 */
771
+	public function setTemplate(Dwoo_ITemplate $tpl)
772
+	{
773
+		$this->template = $tpl;
774
+	}
788 775
 
789
-    /**
790
-     * returns the default compiler factory function for the given resource name
791
-     *
792
-     * @param string $resourceName the resource name
793
-     * @return callback the compiler factory callback
794
-     */
795
-    public function getDefaultCompilerFactory($resourceName)
796
-    {
797
-        return $this->resources[$resourceName]['compiler'];
798
-    }
776
+	/**
777
+	 * sets the default compiler factory function for the given resource name
778
+	 *
779
+	 * a compiler factory must return a Dwoo_ICompiler object pre-configured to fit your needs
780
+	 *
781
+	 * @param string $resourceName the resource name (i.e. file, string)
782
+	 * @param callback $compilerFactory the compiler factory callback
783
+	 */
784
+	public function setDefaultCompilerFactory($resourceName, $compilerFactory)
785
+	{
786
+		$this->resources[$resourceName]['compiler'] = $compilerFactory;
787
+	}
799 788
 
800
-    /**
801
-     * sets the security policy object to enforce some php security settings
802
-     *
803
-     * use this if untrusted persons can modify templates
804
-     *
805
-     * @param Dwoo_Security_Policy $policy the security policy object
806
-     */
807
-    public function setSecurityPolicy(Dwoo_Security_Policy $policy = null)
808
-    {
809
-        $this->securityPolicy = $policy;
810
-    }
789
+	/**
790
+	 * returns the default compiler factory function for the given resource name
791
+	 *
792
+	 * @param string $resourceName the resource name
793
+	 * @return callback the compiler factory callback
794
+	 */
795
+	public function getDefaultCompilerFactory($resourceName)
796
+	{
797
+		return $this->resources[$resourceName]['compiler'];
798
+	}
811 799
 
812
-    /**
813
-     * returns the current security policy object or null by default
814
-     *
815
-     * @return Dwoo_Security_Policy|null the security policy object if any
816
-     */
817
-    public function getSecurityPolicy()
818
-    {
819
-        return $this->securityPolicy;
820
-    }
821
-
822
-    /**
823
-     * sets the object that must be used as a plugin proxy when plugin can't be found
824
-     * by dwoo's loader
825
-     *
826
-     * @param Dwoo_IPluginProxy $pluginProxy the proxy object
827
-     */
828
-    public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy) {
829
-        $this->pluginProxy = $pluginProxy;
830
-    }
800
+	/**
801
+	 * sets the security policy object to enforce some php security settings
802
+	 *
803
+	 * use this if untrusted persons can modify templates
804
+	 *
805
+	 * @param Dwoo_Security_Policy $policy the security policy object
806
+	 */
807
+	public function setSecurityPolicy(Dwoo_Security_Policy $policy = null)
808
+	{
809
+		$this->securityPolicy = $policy;
810
+	}
811
+
812
+	/**
813
+	 * returns the current security policy object or null by default
814
+	 *
815
+	 * @return Dwoo_Security_Policy|null the security policy object if any
816
+	 */
817
+	public function getSecurityPolicy()
818
+	{
819
+		return $this->securityPolicy;
820
+	}
821
+
822
+	/**
823
+	 * sets the object that must be used as a plugin proxy when plugin can't be found
824
+	 * by dwoo's loader
825
+	 *
826
+	 * @param Dwoo_IPluginProxy $pluginProxy the proxy object
827
+	 */
828
+	public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy) {
829
+		$this->pluginProxy = $pluginProxy;
830
+	}
831 831
 
832 832
 	/**
833 833
 	 * returns the current plugin proxy object or null by default
834 834
 	 * @param Dwoo_IPluginProxy|null the proxy object if any
835 835
 	 * @return Dwoo_IPluginProxy
836 836
 	 */
837
-    public function getPluginProxy() {
838
-        return $this->pluginProxy;
839
-    }
837
+	public function getPluginProxy() {
838
+		return $this->pluginProxy;
839
+	}
840 840
 
841
-    /*
841
+	/*
842 842
      * --------- util functions ---------
843 843
      */
844 844
 
845
-    /**
846
-     * [util function] checks whether the given template is cached or not
847
-     *
848
-     * @param Dwoo_ITemplate $tpl the template object
849
-     * @return bool
850
-     */
851
-    public function isCached(Dwoo_ITemplate $tpl)
852
-    {
853
-        return is_string($tpl->getCachedTemplate($this));
854
-    }
845
+	/**
846
+	 * [util function] checks whether the given template is cached or not
847
+	 *
848
+	 * @param Dwoo_ITemplate $tpl the template object
849
+	 * @return bool
850
+	 */
851
+	public function isCached(Dwoo_ITemplate $tpl)
852
+	{
853
+		return is_string($tpl->getCachedTemplate($this));
854
+	}
855 855
 
856 856
 	/**
857 857
 	 * Clear templates inside the compiled directory.
@@ -872,28 +872,28 @@  discard block
 block discarded – undo
872 872
 		return $count;
873 873
 	}
874 874
 
875
-    /**
876
-     * [util function] clears the cached templates if they are older than the given time
877
-     *
878
-     * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
879
-     * @return int the amount of templates cleared
880
-     */
881
-    public function clearCache($olderThan=-1)
882
-    {
875
+	/**
876
+	 * [util function] clears the cached templates if they are older than the given time
877
+	 *
878
+	 * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
879
+	 * @return int the amount of templates cleared
880
+	 */
881
+	public function clearCache($olderThan=-1)
882
+	{
883 883
 		$iterator = new \RecursiveIteratorIterator(
884 884
 			new \RecursiveDirectoryIterator($this->getCacheDir()),
885 885
 			\RecursiveIteratorIterator::SELF_FIRST
886 886
 		);
887
-        $expired = time() - $olderThan;
888
-        $count = 0;
887
+		$expired = time() - $olderThan;
888
+		$count = 0;
889 889
 		/** @var \SplFileInfo $file */
890
-        foreach ($iterator as $file) {
890
+		foreach ($iterator as $file) {
891 891
 			if ($file->isFile() && $file->getCTime() < $expired) {
892 892
 				$count += unlink((string) $file) ? 1 : 0;
893 893
 			}
894
-        }
895
-        return $count;
896
-    }
894
+		}
895
+		return $count;
896
+	}
897 897
 
898 898
 	/**
899 899
 	 * [util function] fetches a template object of the given resource
@@ -906,722 +906,722 @@  discard block
 block discarded – undo
906 906
 	 * @return Dwoo_ITemplate
907 907
 	 * @throws Dwoo_Exception
908 908
 	 */
909
-    public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null)
910
-    {
911
-        if (isset($this->resources[$resourceName])) {
912
-            // TODO could be changed to $this->resources[$resourceName]['class']::templateFactory(..) in 5.3 maybe
913
-            return call_user_func(array($this->resources[$resourceName]['class'], 'templateFactory'), $this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
914
-        } else {
915
-            throw new Dwoo_Exception('Unknown resource type : '.$resourceName);
916
-        }
917
-    }
918
-
919
-    /**
920
-     * [util function] checks if the input is an array or arrayaccess object, optionally it can also check if it's empty
921
-     *
922
-     * @param mixed $value the variable to check
923
-     * @param bool $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
924
-     *                              and return true only if it's not empty
925
-     * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's not an array|arrayaccess (or 0 if $checkIsEmpty is true)
926
-     */
927
-    public function isArray($value, $checkIsEmpty=false)
928
-    {
929
-        if (is_array($value) === true || $value instanceof ArrayAccess) {
930
-            if ($checkIsEmpty === false) {
931
-                return true;
932
-            } else {
933
-                return $this->count($value);
934
-            }
935
-        }
936
-    }
937
-
938
-    /**
939
-     * [util function] checks if the input is an array or a traversable object, optionally it can also check if it's empty
940
-     *
941
-     * @param mixed $value the variable to check
942
-     * @param bool $checkIsEmpty if true, the function will also check if the array|traversable is empty,
943
-     *                              and return true only if it's not empty
944
-     * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's not an array|traversable (or 0 if $checkIsEmpty is true)
945
-     */
946
-    public function isTraversable($value, $checkIsEmpty=false)
947
-    {
948
-        if (is_array($value) === true) {
949
-            if ($checkIsEmpty === false) {
950
-                return true;
951
-            } else {
952
-                return count($value) > 0;
953
-            }
954
-        } elseif ($value instanceof Traversable) {
955
-            if ($checkIsEmpty === false) {
956
-                return true;
957
-            } else {
958
-                return $this->count($value);
959
-            }
960
-        }
961
-        return false;
962
-    }
963
-
964
-    /**
965
-     * [util function] counts an array or arrayaccess/traversable object
966
-     * @param mixed $value
967
-     * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't, and 0 for empty elements
968
-     */
969
-    public function count($value)
970
-    {
971
-        if (is_array($value) === true || $value instanceof Countable) {
972
-            return count($value);
973
-        } elseif ($value instanceof ArrayAccess) {
974
-            if ($value->offsetExists(0)) {
975
-                return true;
976
-            }
977
-        } elseif ($value instanceof Iterator) {
978
-            $value->rewind();
979
-            if ($value->valid()) {
980
-                return true;
981
-            }
982
-        } elseif ($value instanceof Traversable) {
983
-            foreach ($value as $dummy) {
984
-                return true;
985
-            }
986
-        }
987
-        return 0;
988
-    }
989
-
990
-    /**
991
-     * [util function] triggers a dwoo error
992
-     *
993
-     * @param string $message the error message
994
-     * @param int $level the error level, one of the PHP's E_* constants
995
-     */
996
-    public function triggerError($message, $level=E_USER_NOTICE)
997
-    {
998
-        if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
999
-            $tplIdentifier = $this->template->getResourceName();
1000
-        }
1001
-        trigger_error('Dwoo error (in '.$tplIdentifier.') : '.$message, $level);
1002
-    }
1003
-
1004
-    /*
909
+	public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null)
910
+	{
911
+		if (isset($this->resources[$resourceName])) {
912
+			// TODO could be changed to $this->resources[$resourceName]['class']::templateFactory(..) in 5.3 maybe
913
+			return call_user_func(array($this->resources[$resourceName]['class'], 'templateFactory'), $this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
914
+		} else {
915
+			throw new Dwoo_Exception('Unknown resource type : '.$resourceName);
916
+		}
917
+	}
918
+
919
+	/**
920
+	 * [util function] checks if the input is an array or arrayaccess object, optionally it can also check if it's empty
921
+	 *
922
+	 * @param mixed $value the variable to check
923
+	 * @param bool $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
924
+	 *                              and return true only if it's not empty
925
+	 * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's not an array|arrayaccess (or 0 if $checkIsEmpty is true)
926
+	 */
927
+	public function isArray($value, $checkIsEmpty=false)
928
+	{
929
+		if (is_array($value) === true || $value instanceof ArrayAccess) {
930
+			if ($checkIsEmpty === false) {
931
+				return true;
932
+			} else {
933
+				return $this->count($value);
934
+			}
935
+		}
936
+	}
937
+
938
+	/**
939
+	 * [util function] checks if the input is an array or a traversable object, optionally it can also check if it's empty
940
+	 *
941
+	 * @param mixed $value the variable to check
942
+	 * @param bool $checkIsEmpty if true, the function will also check if the array|traversable is empty,
943
+	 *                              and return true only if it's not empty
944
+	 * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's not an array|traversable (or 0 if $checkIsEmpty is true)
945
+	 */
946
+	public function isTraversable($value, $checkIsEmpty=false)
947
+	{
948
+		if (is_array($value) === true) {
949
+			if ($checkIsEmpty === false) {
950
+				return true;
951
+			} else {
952
+				return count($value) > 0;
953
+			}
954
+		} elseif ($value instanceof Traversable) {
955
+			if ($checkIsEmpty === false) {
956
+				return true;
957
+			} else {
958
+				return $this->count($value);
959
+			}
960
+		}
961
+		return false;
962
+	}
963
+
964
+	/**
965
+	 * [util function] counts an array or arrayaccess/traversable object
966
+	 * @param mixed $value
967
+	 * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't, and 0 for empty elements
968
+	 */
969
+	public function count($value)
970
+	{
971
+		if (is_array($value) === true || $value instanceof Countable) {
972
+			return count($value);
973
+		} elseif ($value instanceof ArrayAccess) {
974
+			if ($value->offsetExists(0)) {
975
+				return true;
976
+			}
977
+		} elseif ($value instanceof Iterator) {
978
+			$value->rewind();
979
+			if ($value->valid()) {
980
+				return true;
981
+			}
982
+		} elseif ($value instanceof Traversable) {
983
+			foreach ($value as $dummy) {
984
+				return true;
985
+			}
986
+		}
987
+		return 0;
988
+	}
989
+
990
+	/**
991
+	 * [util function] triggers a dwoo error
992
+	 *
993
+	 * @param string $message the error message
994
+	 * @param int $level the error level, one of the PHP's E_* constants
995
+	 */
996
+	public function triggerError($message, $level=E_USER_NOTICE)
997
+	{
998
+		if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
999
+			$tplIdentifier = $this->template->getResourceName();
1000
+		}
1001
+		trigger_error('Dwoo error (in '.$tplIdentifier.') : '.$message, $level);
1002
+	}
1003
+
1004
+	/*
1005 1005
      * --------- runtime functions ---------
1006 1006
      */
1007 1007
 
1008
-    /**
1009
-     * [runtime function] adds a block to the block stack
1010
-     *
1011
-     * @param string $blockName the block name (without Dwoo_Plugin_ prefix)
1012
-     * @param array $args the arguments to be passed to the block's init() function
1013
-     * @return Dwoo_Block_Plugin the newly created block
1014
-     */
1015
-    public function addStack($blockName, array $args=array())
1016
-    {
1017
-        if (isset($this->plugins[$blockName])) {
1018
-            $class = $this->plugins[$blockName]['class'];
1019
-        } else {
1020
-            $class = 'Dwoo_Plugin_'.$blockName;
1021
-        }
1022
-
1023
-        if ($this->curBlock !== null) {
1024
-            $this->curBlock->buffer(ob_get_contents());
1025
-            ob_clean();
1026
-        } else {
1027
-            $this->buffer .= ob_get_contents();
1028
-            ob_clean();
1029
-        }
1030
-
1031
-        $block = new $class($this);
1032
-
1033
-        $cnt = count($args);
1034
-        if ($cnt===0) {
1035
-            $block->init();
1036
-        } elseif ($cnt===1) {
1037
-            $block->init($args[0]);
1038
-        } elseif ($cnt===2) {
1039
-            $block->init($args[0], $args[1]);
1040
-        } elseif ($cnt===3) {
1041
-            $block->init($args[0], $args[1], $args[2]);
1042
-        } elseif ($cnt===4) {
1043
-            $block->init($args[0], $args[1], $args[2], $args[3]);
1044
-        } else {
1045
-            call_user_func_array(array($block,'init'), $args);
1046
-        }
1047
-
1048
-        $this->stack[] = $this->curBlock = $block;
1049
-        return $block;
1050
-    }
1051
-
1052
-    /**
1053
-     * [runtime function] removes the plugin at the top of the block stack
1054
-     *
1055
-     * calls the block buffer() function, followed by a call to end()
1056
-     * and finally a call to process()
1057
-     */
1058
-    public function delStack()
1059
-    {
1060
-        $args = func_get_args();
1061
-
1062
-        $this->curBlock->buffer(ob_get_contents());
1063
-        ob_clean();
1064
-
1065
-        $cnt = count($args);
1066
-        if ($cnt===0) {
1067
-            $this->curBlock->end();
1068
-        } elseif ($cnt===1) {
1069
-            $this->curBlock->end($args[0]);
1070
-        } elseif ($cnt===2) {
1071
-            $this->curBlock->end($args[0], $args[1]);
1072
-        } elseif ($cnt===3) {
1073
-            $this->curBlock->end($args[0], $args[1], $args[2]);
1074
-        } elseif ($cnt===4) {
1075
-            $this->curBlock->end($args[0], $args[1], $args[2], $args[3]);
1076
-        } else {
1077
-            call_user_func_array(array($this->curBlock, 'end'), $args);
1078
-        }
1079
-
1080
-        $tmp = array_pop($this->stack);
1081
-
1082
-        if (count($this->stack) > 0) {
1083
-            $this->curBlock = end($this->stack);
1084
-            $this->curBlock->buffer($tmp->process());
1085
-        } else {
1086
-            if($this->buffer !== '') {
1087
-                echo $this->buffer;
1088
-                $this->buffer = '';
1089
-            }
1090
-            $this->curBlock = null;
1091
-            echo $tmp->process();
1092
-        }
1093
-
1094
-        unset($tmp);
1095
-    }
1096
-
1097
-    /**
1098
-     * [runtime function] returns the parent block of the given block
1099
-     *
1100
-     * @param Dwoo_Block_Plugin $block
1101
-     * @return Dwoo_Block_Plugin|false if the given block isn't in the stack
1102
-     */
1103
-    public function getParentBlock(Dwoo_Block_Plugin $block)
1104
-    {
1105
-        $index = array_search($block, $this->stack, true);
1106
-        if ($index !== false && $index > 0) {
1107
-            return $this->stack[$index-1];
1108
-        }
1109
-        return false;
1110
-    }
1111
-
1112
-    /**
1113
-     * [runtime function] finds the closest block of the given type, starting at the top of the stack
1114
-     *
1115
-     * @param string $type the type of plugin you want to find
1116
-     * @return Dwoo_Block_Plugin|false if no plugin of such type is in the stack
1117
-     */
1118
-    public function findBlock($type)
1119
-    {
1120
-        if (isset($this->plugins[$type])) {
1121
-            $type = $this->plugins[$type]['class'];
1122
-        } else {
1123
-            $type = 'Dwoo_Plugin_'.str_replace('Dwoo_Plugin_', '', $type);
1124
-        }
1125
-
1126
-        $keys = array_keys($this->stack);
1127
-        while (($key = array_pop($keys)) !== false) {
1128
-            if ($this->stack[$key] instanceof $type) {
1129
-                return $this->stack[$key];
1130
-            }
1131
-        }
1132
-        return false;
1133
-    }
1134
-
1135
-    /**
1136
-     * [runtime function] returns a Dwoo_Plugin of the given class
1137
-     *
1138
-     * this is so a single instance of every class plugin is created at each template run,
1139
-     * allowing class plugins to have "per-template-run" static variables
1140
-     *
1141
-     * @private
1142
-     * @param string $class the class name
1143
-     * @return mixed an object of the given class
1144
-     */
1145
-    public function getObjectPlugin($class)
1146
-    {
1147
-        if (isset($this->runtimePlugins[$class])) {
1148
-            return $this->runtimePlugins[$class];
1149
-        }
1150
-        return $this->runtimePlugins[$class] = new $class($this);
1151
-    }
1152
-
1153
-    /**
1154
-     * [runtime function] calls the process() method of the given class-plugin name
1155
-     *
1156
-     * @param string $plugName the class plugin name (without Dwoo_Plugin_ prefix)
1157
-     * @param array $params an array of parameters to send to the process() method
1158
-     * @return string the process() return value
1159
-     */
1160
-    public function classCall($plugName, array $params = array())
1161
-    {
1162
-        $class = 'Dwoo_Plugin_'.$plugName;
1163
-
1164
-        $plugin = $this->getObjectPlugin($class);
1165
-
1166
-        $cnt = count($params);
1167
-        if ($cnt===0) {
1168
-            return $plugin->process();
1169
-        } elseif ($cnt===1) {
1170
-            return $plugin->process($params[0]);
1171
-        } elseif ($cnt===2) {
1172
-            return $plugin->process($params[0], $params[1]);
1173
-        } elseif ($cnt===3) {
1174
-            return $plugin->process($params[0], $params[1], $params[2]);
1175
-        } elseif ($cnt===4) {
1176
-            return $plugin->process($params[0], $params[1], $params[2], $params[3]);
1177
-        } else {
1178
-            return call_user_func_array(array($plugin, 'process'), $params);
1179
-        }
1180
-    }
1181
-
1182
-    /**
1183
-     * [runtime function] calls a php function
1184
-     *
1185
-     * @param string $callback the function to call
1186
-     * @param array $params an array of parameters to send to the function
1187
-     * @return mixed the return value of the called function
1188
-     */
1189
-    public function arrayMap($callback, array $params)
1190
-    {
1191
-        if ($params[0] === $this) {
1192
-            $addThis = true;
1193
-            array_shift($params);
1194
-        }
1195
-        if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1196
-            if (empty($params[0])) {
1197
-                return $params[0];
1198
-            }
1199
-
1200
-            // array map
1201
-            $out = array();
1202
-            $cnt = count($params);
1203
-
1204
-            if (isset($addThis)) {
1205
-                array_unshift($params, $this);
1206
-                $items = $params[1];
1207
-                $keys = array_keys($items);
1208
-
1209
-                if (is_string($callback) === false) {
1210
-                    while (($i = array_shift($keys)) !== null) {
1211
-                        $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params);
1212
-                    }
1213
-                } elseif ($cnt===1) {
1214
-                    while (($i = array_shift($keys)) !== null) {
1215
-                        $out[] = $callback($this, $items[$i]);
1216
-                    }
1217
-                } elseif ($cnt===2) {
1218
-                    while (($i = array_shift($keys)) !== null) {
1219
-                        $out[] = $callback($this, $items[$i], $params[2]);
1220
-                    }
1221
-                } elseif ($cnt===3) {
1222
-                    while (($i = array_shift($keys)) !== null) {
1223
-                        $out[] = $callback($this, $items[$i], $params[2], $params[3]);
1224
-                    }
1225
-                } else {
1226
-                    while (($i = array_shift($keys)) !== null) {
1227
-                        $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params);
1228
-                    }
1229
-                }
1230
-            } else {
1231
-                $items = $params[0];
1232
-                $keys = array_keys($items);
1233
-
1234
-                if (is_string($callback) === false) {
1235
-                    while (($i = array_shift($keys)) !== null) {
1236
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1237
-                    }
1238
-                } elseif ($cnt===1) {
1239
-                    while (($i = array_shift($keys)) !== null) {
1240
-                        $out[] = $callback($items[$i]);
1241
-                    }
1242
-                } elseif ($cnt===2) {
1243
-                    while (($i = array_shift($keys)) !== null) {
1244
-                        $out[] = $callback($items[$i], $params[1]);
1245
-                    }
1246
-                } elseif ($cnt===3) {
1247
-                    while (($i = array_shift($keys)) !== null) {
1248
-                        $out[] = $callback($items[$i], $params[1], $params[2]);
1249
-                    }
1250
-                } elseif ($cnt===4) {
1251
-                    while (($i = array_shift($keys)) !== null) {
1252
-                        $out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1253
-                    }
1254
-                } else {
1255
-                    while (($i = array_shift($keys)) !== null) {
1256
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1257
-                    }
1258
-                }
1259
-            }
1260
-            return $out;
1261
-        } else {
1262
-            return $params[0];
1263
-        }
1264
-    }
1265
-
1266
-    /**
1267
-     * [runtime function] reads a variable into the given data array
1268
-     *
1269
-     * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1270
-     * @param mixed $data the data array or object to read from
1271
-     * @param bool $safeRead if true, the function will check whether the index exists to prevent any notices from being output
1272
-     * @return mixed
1273
-     */
1274
-    public function readVarInto($varstr, $data, $safeRead = false)
1275
-    {
1276
-        if ($data === null) {
1277
-            return null;
1278
-        }
1279
-
1280
-        if (is_array($varstr) === false) {
1281
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1282
-        } else {
1283
-            $m = $varstr;
1284
-        }
1285
-        unset($varstr);
1286
-
1287
-        while (list($k, $sep) = each($m[1])) {
1288
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1289
-                // strip enclosing quotes if present
1290
-                $m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1291
-
1292
-                if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1293
-                    $data = $data[$m[2][$k]];
1294
-                } else {
1295
-                    return null;
1296
-                }
1297
-            } else {
1298
-                if (is_object($data) && ($safeRead === false || isset($data->$m[2][$k]))) {
1299
-                    $data = $data->$m[2][$k];
1300
-                } else {
1301
-                    return null;
1302
-                }
1303
-            }
1304
-        }
1305
-
1306
-        return $data;
1307
-    }
1308
-
1309
-    /**
1310
-     * [runtime function] reads a variable into the parent scope
1311
-     *
1312
-     * @param int $parentLevels the amount of parent levels to go from the current scope
1313
-     * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1314
-     * @return mixed
1315
-     */
1316
-    public function readParentVar($parentLevels, $varstr = null)
1317
-    {
1318
-        $tree = $this->scopeTree;
1319
-        $cur = $this->data;
1320
-
1321
-        while ($parentLevels--!==0) {
1322
-            array_pop($tree);
1323
-        }
1324
-
1325
-        while (($i = array_shift($tree)) !== null) {
1326
-            if (is_object($cur)) {
1327
-                $cur = $cur->$i;
1328
-            } else {
1329
-                $cur = $cur[$i];
1330
-            }
1331
-        }
1332
-
1333
-        if ($varstr!==null) {
1334
-            return $this->readVarInto($varstr, $cur);
1335
-        } else {
1336
-            return $cur;
1337
-        }
1338
-    }
1339
-
1340
-    /**
1341
-     * [runtime function] reads a variable into the current scope
1342
-     *
1343
-     * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1344
-     * @return mixed
1345
-     */
1346
-    public function readVar($varstr)
1347
-    {
1348
-        if (is_array($varstr)===true) {
1349
-            $m = $varstr;
1350
-            unset($varstr);
1351
-        } else {
1352
-            if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1353
-                if ($varstr === 'dwoo') {
1354
-                    return $this->globals;
1355
-                } elseif ($varstr === '__' || $varstr === '_root' ) {
1356
-                    return $this->data;
1357
-                } elseif ($varstr === '_' || $varstr === '_parent') {
1358
-                    $varstr = '.'.$varstr;
1359
-                    $tree = $this->scopeTree;
1360
-                    $cur = $this->data;
1361
-                    array_pop($tree);
1362
-
1363
-                    while (($i = array_shift($tree)) !== null) {
1364
-                        if (is_object($cur)) {
1365
-                            $cur = $cur->$i;
1366
-                        } else {
1367
-                            $cur = $cur[$i];
1368
-                        }
1369
-                    }
1370
-
1371
-                    return $cur;
1372
-                }
1373
-
1374
-                $cur = $this->scope;
1375
-
1376
-                if (isset($cur[$varstr])) {
1377
-                    return $cur[$varstr];
1378
-                } else {
1379
-                    return null;
1380
-                }
1381
-            }
1382
-
1383
-            if (substr($varstr, 0, 1) === '.') {
1384
-                $varstr = 'dwoo'.$varstr;
1385
-            }
1386
-
1387
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1388
-        }
1389
-
1390
-        $i = $m[2][0];
1391
-        if ($i === 'dwoo') {
1392
-            $cur = $this->globals;
1393
-            array_shift($m[2]);
1394
-            array_shift($m[1]);
1395
-            switch ($m[2][0]) {
1396
-
1397
-            case 'get':
1398
-                $cur = $_GET;
1399
-                break;
1400
-            case 'post':
1401
-                $cur = $_POST;
1402
-                break;
1403
-            case 'session':
1404
-                $cur = $_SESSION;
1405
-                break;
1406
-            case 'cookies':
1407
-            case 'cookie':
1408
-                $cur = $_COOKIE;
1409
-                break;
1410
-            case 'server':
1411
-                $cur = $_SERVER;
1412
-                break;
1413
-            case 'env':
1414
-                $cur = $_ENV;
1415
-                break;
1416
-            case 'request':
1417
-                $cur = $_REQUEST;
1418
-                break;
1419
-            case 'const':
1420
-                array_shift($m[2]);
1421
-                if (defined($m[2][0])) {
1422
-                    return constant($m[2][0]);
1423
-                } else {
1424
-                    return null;
1425
-                }
1426
-
1427
-            }
1428
-            if ($cur !== $this->globals) {
1429
-                array_shift($m[2]);
1430
-                array_shift($m[1]);
1431
-            }
1432
-        } elseif ($i === '__' || $i === '_root') {
1433
-            $cur = $this->data;
1434
-            array_shift($m[2]);
1435
-            array_shift($m[1]);
1436
-        } elseif ($i === '_' || $i === '_parent') {
1437
-            $tree = $this->scopeTree;
1438
-            $cur = $this->data;
1439
-
1440
-            while (true) {
1441
-                array_pop($tree);
1442
-                array_shift($m[2]);
1443
-                array_shift($m[1]);
1444
-                if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1445
-                    continue;
1446
-                }
1447
-
1448
-                while (($i = array_shift($tree)) !== null) {
1449
-                    if (is_object($cur)) {
1450
-                        $cur = $cur->$i;
1451
-                    } else {
1452
-                        $cur = $cur[$i];
1453
-                    }
1454
-                }
1455
-                break;
1456
-            }
1457
-        } else {
1458
-            $cur = $this->scope;
1459
-        }
1460
-
1461
-        while (list($k, $sep) = each($m[1])) {
1462
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1463
-                if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1464
-                    $cur = $cur[$m[2][$k]];
1465
-                } else {
1466
-                    return null;
1467
-                }
1468
-            } elseif ($sep === '->') {
1469
-                if (is_object($cur)) {
1470
-                    $cur = $cur->$m[2][$k];
1471
-                } else {
1472
-                    return null;
1473
-                }
1474
-            } else {
1475
-                return null;
1476
-            }
1477
-        }
1478
-
1479
-        return $cur;
1480
-    }
1481
-
1482
-    /**
1483
-     * [runtime function] assign the value to the given variable
1484
-     *
1485
-     * @param mixed $value the value to assign
1486
-     * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1487
-     * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1488
-     */
1489
-    public function assignInScope($value, $scope)
1490
-    {
1491
-        $tree =& $this->scopeTree;
1492
-        $data =& $this->data;
1493
-
1494
-        if (!is_string($scope)) {
1495
-            $this->triggerError('Assignments must be done into strings, ('.gettype($scope).') '.var_export($scope, true).' given', E_USER_ERROR);
1496
-        }
1497
-        if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1498
-            $this->scope[$scope] = $value;
1499
-        } else {
1500
-            // TODO handle _root/_parent scopes ?
1501
-            preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1502
-
1503
-            $cur =& $this->scope;
1504
-            $last = array(array_pop($m[1]), array_pop($m[2]));
1505
-
1506
-            while (list($k, $sep) = each($m[1])) {
1507
-                if ($sep === '.' || $sep === '[' || $sep === '') {
1508
-                    if (is_array($cur) === false) {
1509
-                        $cur = array();
1510
-                    }
1511
-                    $cur =& $cur[$m[2][$k]];
1512
-                } elseif ($sep === '->') {
1513
-                    if (is_object($cur) === false) {
1514
-                        $cur = new stdClass;
1515
-                    }
1516
-                    $cur =& $cur->$m[2][$k];
1517
-                } else {
1518
-                    return false;
1519
-                }
1520
-            }
1521
-
1522
-            if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1523
-                if (is_array($cur) === false) {
1524
-                    $cur = array();
1525
-                }
1526
-                $cur[$last[1]] = $value;
1527
-            } elseif ($last[0] === '->') {
1528
-                if (is_object($cur) === false) {
1529
-                    $cur = new stdClass;
1530
-                }
1531
-                $cur->$last[1] = $value;
1532
-            } else {
1533
-                return false;
1534
-            }
1535
-        }
1536
-    }
1537
-
1538
-    /**
1539
-     * [runtime function] sets the scope to the given scope string or array
1540
-     *
1541
-     * @param mixed $scope a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1542
-     * @param bool $absolute if true, the scope is set from the top level scope and not from the current scope
1543
-     * @return array the current scope tree
1544
-     */
1545
-    public function setScope($scope, $absolute = false)
1546
-    {
1547
-        $old = $this->scopeTree;
1548
-
1549
-        if (is_string($scope)===true) {
1550
-            $scope = explode('.', $scope);
1551
-        }
1552
-
1553
-        if ($absolute===true) {
1554
-            $this->scope =& $this->data;
1555
-            $this->scopeTree = array();
1556
-        }
1557
-
1558
-        while (($bit = array_shift($scope)) !== null) {
1559
-            if ($bit === '_' || $bit === '_parent') {
1560
-                array_pop($this->scopeTree);
1561
-                $this->scope =& $this->data;
1562
-                $cnt = count($this->scopeTree);
1563
-                for ($i=0;$i<$cnt;$i++)
1564
-                    $this->scope =& $this->scope[$this->scopeTree[$i]];
1565
-            } elseif ($bit === '__' || $bit === '_root') {
1566
-                $this->scope =& $this->data;
1567
-                $this->scopeTree = array();
1568
-            } elseif (isset($this->scope[$bit])) {
1569
-                if($this->scope instanceof ArrayAccess) {
1570
-                    $tmp = $this->scope[$bit];
1571
-                    $this->scope =& $tmp;
1572
-                } else {
1573
-                    $this->scope =& $this->scope[$bit];
1574
-                }
1575
-                $this->scopeTree[] = $bit;
1576
-            } else {
1577
-                unset($this->scope);
1578
-                $this->scope = null;
1579
-            }
1580
-        }
1581
-
1582
-        return $old;
1583
-    }
1584
-
1585
-    /**
1586
-     * [runtime function] returns the entire data array
1587
-     *
1588
-     * @return array
1589
-     */
1590
-    public function getData()
1591
-    {
1592
-        return $this->data;
1593
-    }
1008
+	/**
1009
+	 * [runtime function] adds a block to the block stack
1010
+	 *
1011
+	 * @param string $blockName the block name (without Dwoo_Plugin_ prefix)
1012
+	 * @param array $args the arguments to be passed to the block's init() function
1013
+	 * @return Dwoo_Block_Plugin the newly created block
1014
+	 */
1015
+	public function addStack($blockName, array $args=array())
1016
+	{
1017
+		if (isset($this->plugins[$blockName])) {
1018
+			$class = $this->plugins[$blockName]['class'];
1019
+		} else {
1020
+			$class = 'Dwoo_Plugin_'.$blockName;
1021
+		}
1594 1022
 
1595
-    /**
1596
-     * [runtime function] sets a return value for the currently running template
1597
-     *
1598
-     * @param string $name var name
1599
-     * @param mixed $value var value
1600
-     */
1601
-    public function setReturnValue($name, $value)
1602
-    {
1603
-        $this->returnData[$name] = $value;
1604
-    }
1023
+		if ($this->curBlock !== null) {
1024
+			$this->curBlock->buffer(ob_get_contents());
1025
+			ob_clean();
1026
+		} else {
1027
+			$this->buffer .= ob_get_contents();
1028
+			ob_clean();
1029
+		}
1605 1030
 
1606
-    /**
1607
-     * [runtime function] retrieves the return values set by the template
1608
-     *
1609
-     * @return array
1610
-     */
1611
-    public function getReturnValues()
1612
-    {
1613
-        return $this->returnData;
1614
-    }
1031
+		$block = new $class($this);
1032
+
1033
+		$cnt = count($args);
1034
+		if ($cnt===0) {
1035
+			$block->init();
1036
+		} elseif ($cnt===1) {
1037
+			$block->init($args[0]);
1038
+		} elseif ($cnt===2) {
1039
+			$block->init($args[0], $args[1]);
1040
+		} elseif ($cnt===3) {
1041
+			$block->init($args[0], $args[1], $args[2]);
1042
+		} elseif ($cnt===4) {
1043
+			$block->init($args[0], $args[1], $args[2], $args[3]);
1044
+		} else {
1045
+			call_user_func_array(array($block,'init'), $args);
1046
+		}
1615 1047
 
1616
-    /**
1617
-     * [runtime function] returns a reference to the current scope
1618
-     *
1619
-     * @return &mixed
1620
-     */
1621
-    public function &getScope()
1622
-    {
1623
-        return $this->scope;
1624
-    }
1048
+		$this->stack[] = $this->curBlock = $block;
1049
+		return $block;
1050
+	}
1051
+
1052
+	/**
1053
+	 * [runtime function] removes the plugin at the top of the block stack
1054
+	 *
1055
+	 * calls the block buffer() function, followed by a call to end()
1056
+	 * and finally a call to process()
1057
+	 */
1058
+	public function delStack()
1059
+	{
1060
+		$args = func_get_args();
1061
+
1062
+		$this->curBlock->buffer(ob_get_contents());
1063
+		ob_clean();
1064
+
1065
+		$cnt = count($args);
1066
+		if ($cnt===0) {
1067
+			$this->curBlock->end();
1068
+		} elseif ($cnt===1) {
1069
+			$this->curBlock->end($args[0]);
1070
+		} elseif ($cnt===2) {
1071
+			$this->curBlock->end($args[0], $args[1]);
1072
+		} elseif ($cnt===3) {
1073
+			$this->curBlock->end($args[0], $args[1], $args[2]);
1074
+		} elseif ($cnt===4) {
1075
+			$this->curBlock->end($args[0], $args[1], $args[2], $args[3]);
1076
+		} else {
1077
+			call_user_func_array(array($this->curBlock, 'end'), $args);
1078
+		}
1079
+
1080
+		$tmp = array_pop($this->stack);
1081
+
1082
+		if (count($this->stack) > 0) {
1083
+			$this->curBlock = end($this->stack);
1084
+			$this->curBlock->buffer($tmp->process());
1085
+		} else {
1086
+			if($this->buffer !== '') {
1087
+				echo $this->buffer;
1088
+				$this->buffer = '';
1089
+			}
1090
+			$this->curBlock = null;
1091
+			echo $tmp->process();
1092
+		}
1093
+
1094
+		unset($tmp);
1095
+	}
1096
+
1097
+	/**
1098
+	 * [runtime function] returns the parent block of the given block
1099
+	 *
1100
+	 * @param Dwoo_Block_Plugin $block
1101
+	 * @return Dwoo_Block_Plugin|false if the given block isn't in the stack
1102
+	 */
1103
+	public function getParentBlock(Dwoo_Block_Plugin $block)
1104
+	{
1105
+		$index = array_search($block, $this->stack, true);
1106
+		if ($index !== false && $index > 0) {
1107
+			return $this->stack[$index-1];
1108
+		}
1109
+		return false;
1110
+	}
1111
+
1112
+	/**
1113
+	 * [runtime function] finds the closest block of the given type, starting at the top of the stack
1114
+	 *
1115
+	 * @param string $type the type of plugin you want to find
1116
+	 * @return Dwoo_Block_Plugin|false if no plugin of such type is in the stack
1117
+	 */
1118
+	public function findBlock($type)
1119
+	{
1120
+		if (isset($this->plugins[$type])) {
1121
+			$type = $this->plugins[$type]['class'];
1122
+		} else {
1123
+			$type = 'Dwoo_Plugin_'.str_replace('Dwoo_Plugin_', '', $type);
1124
+		}
1125
+
1126
+		$keys = array_keys($this->stack);
1127
+		while (($key = array_pop($keys)) !== false) {
1128
+			if ($this->stack[$key] instanceof $type) {
1129
+				return $this->stack[$key];
1130
+			}
1131
+		}
1132
+		return false;
1133
+	}
1134
+
1135
+	/**
1136
+	 * [runtime function] returns a Dwoo_Plugin of the given class
1137
+	 *
1138
+	 * this is so a single instance of every class plugin is created at each template run,
1139
+	 * allowing class plugins to have "per-template-run" static variables
1140
+	 *
1141
+	 * @private
1142
+	 * @param string $class the class name
1143
+	 * @return mixed an object of the given class
1144
+	 */
1145
+	public function getObjectPlugin($class)
1146
+	{
1147
+		if (isset($this->runtimePlugins[$class])) {
1148
+			return $this->runtimePlugins[$class];
1149
+		}
1150
+		return $this->runtimePlugins[$class] = new $class($this);
1151
+	}
1152
+
1153
+	/**
1154
+	 * [runtime function] calls the process() method of the given class-plugin name
1155
+	 *
1156
+	 * @param string $plugName the class plugin name (without Dwoo_Plugin_ prefix)
1157
+	 * @param array $params an array of parameters to send to the process() method
1158
+	 * @return string the process() return value
1159
+	 */
1160
+	public function classCall($plugName, array $params = array())
1161
+	{
1162
+		$class = 'Dwoo_Plugin_'.$plugName;
1163
+
1164
+		$plugin = $this->getObjectPlugin($class);
1165
+
1166
+		$cnt = count($params);
1167
+		if ($cnt===0) {
1168
+			return $plugin->process();
1169
+		} elseif ($cnt===1) {
1170
+			return $plugin->process($params[0]);
1171
+		} elseif ($cnt===2) {
1172
+			return $plugin->process($params[0], $params[1]);
1173
+		} elseif ($cnt===3) {
1174
+			return $plugin->process($params[0], $params[1], $params[2]);
1175
+		} elseif ($cnt===4) {
1176
+			return $plugin->process($params[0], $params[1], $params[2], $params[3]);
1177
+		} else {
1178
+			return call_user_func_array(array($plugin, 'process'), $params);
1179
+		}
1180
+	}
1181
+
1182
+	/**
1183
+	 * [runtime function] calls a php function
1184
+	 *
1185
+	 * @param string $callback the function to call
1186
+	 * @param array $params an array of parameters to send to the function
1187
+	 * @return mixed the return value of the called function
1188
+	 */
1189
+	public function arrayMap($callback, array $params)
1190
+	{
1191
+		if ($params[0] === $this) {
1192
+			$addThis = true;
1193
+			array_shift($params);
1194
+		}
1195
+		if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1196
+			if (empty($params[0])) {
1197
+				return $params[0];
1198
+			}
1199
+
1200
+			// array map
1201
+			$out = array();
1202
+			$cnt = count($params);
1203
+
1204
+			if (isset($addThis)) {
1205
+				array_unshift($params, $this);
1206
+				$items = $params[1];
1207
+				$keys = array_keys($items);
1208
+
1209
+				if (is_string($callback) === false) {
1210
+					while (($i = array_shift($keys)) !== null) {
1211
+						$out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params);
1212
+					}
1213
+				} elseif ($cnt===1) {
1214
+					while (($i = array_shift($keys)) !== null) {
1215
+						$out[] = $callback($this, $items[$i]);
1216
+					}
1217
+				} elseif ($cnt===2) {
1218
+					while (($i = array_shift($keys)) !== null) {
1219
+						$out[] = $callback($this, $items[$i], $params[2]);
1220
+					}
1221
+				} elseif ($cnt===3) {
1222
+					while (($i = array_shift($keys)) !== null) {
1223
+						$out[] = $callback($this, $items[$i], $params[2], $params[3]);
1224
+					}
1225
+				} else {
1226
+					while (($i = array_shift($keys)) !== null) {
1227
+						$out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params);
1228
+					}
1229
+				}
1230
+			} else {
1231
+				$items = $params[0];
1232
+				$keys = array_keys($items);
1233
+
1234
+				if (is_string($callback) === false) {
1235
+					while (($i = array_shift($keys)) !== null) {
1236
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1237
+					}
1238
+				} elseif ($cnt===1) {
1239
+					while (($i = array_shift($keys)) !== null) {
1240
+						$out[] = $callback($items[$i]);
1241
+					}
1242
+				} elseif ($cnt===2) {
1243
+					while (($i = array_shift($keys)) !== null) {
1244
+						$out[] = $callback($items[$i], $params[1]);
1245
+					}
1246
+				} elseif ($cnt===3) {
1247
+					while (($i = array_shift($keys)) !== null) {
1248
+						$out[] = $callback($items[$i], $params[1], $params[2]);
1249
+					}
1250
+				} elseif ($cnt===4) {
1251
+					while (($i = array_shift($keys)) !== null) {
1252
+						$out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1253
+					}
1254
+				} else {
1255
+					while (($i = array_shift($keys)) !== null) {
1256
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1257
+					}
1258
+				}
1259
+			}
1260
+			return $out;
1261
+		} else {
1262
+			return $params[0];
1263
+		}
1264
+	}
1265
+
1266
+	/**
1267
+	 * [runtime function] reads a variable into the given data array
1268
+	 *
1269
+	 * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1270
+	 * @param mixed $data the data array or object to read from
1271
+	 * @param bool $safeRead if true, the function will check whether the index exists to prevent any notices from being output
1272
+	 * @return mixed
1273
+	 */
1274
+	public function readVarInto($varstr, $data, $safeRead = false)
1275
+	{
1276
+		if ($data === null) {
1277
+			return null;
1278
+		}
1279
+
1280
+		if (is_array($varstr) === false) {
1281
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1282
+		} else {
1283
+			$m = $varstr;
1284
+		}
1285
+		unset($varstr);
1286
+
1287
+		while (list($k, $sep) = each($m[1])) {
1288
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1289
+				// strip enclosing quotes if present
1290
+				$m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1291
+
1292
+				if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1293
+					$data = $data[$m[2][$k]];
1294
+				} else {
1295
+					return null;
1296
+				}
1297
+			} else {
1298
+				if (is_object($data) && ($safeRead === false || isset($data->$m[2][$k]))) {
1299
+					$data = $data->$m[2][$k];
1300
+				} else {
1301
+					return null;
1302
+				}
1303
+			}
1304
+		}
1305
+
1306
+		return $data;
1307
+	}
1308
+
1309
+	/**
1310
+	 * [runtime function] reads a variable into the parent scope
1311
+	 *
1312
+	 * @param int $parentLevels the amount of parent levels to go from the current scope
1313
+	 * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1314
+	 * @return mixed
1315
+	 */
1316
+	public function readParentVar($parentLevels, $varstr = null)
1317
+	{
1318
+		$tree = $this->scopeTree;
1319
+		$cur = $this->data;
1320
+
1321
+		while ($parentLevels--!==0) {
1322
+			array_pop($tree);
1323
+		}
1324
+
1325
+		while (($i = array_shift($tree)) !== null) {
1326
+			if (is_object($cur)) {
1327
+				$cur = $cur->$i;
1328
+			} else {
1329
+				$cur = $cur[$i];
1330
+			}
1331
+		}
1332
+
1333
+		if ($varstr!==null) {
1334
+			return $this->readVarInto($varstr, $cur);
1335
+		} else {
1336
+			return $cur;
1337
+		}
1338
+	}
1339
+
1340
+	/**
1341
+	 * [runtime function] reads a variable into the current scope
1342
+	 *
1343
+	 * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1344
+	 * @return mixed
1345
+	 */
1346
+	public function readVar($varstr)
1347
+	{
1348
+		if (is_array($varstr)===true) {
1349
+			$m = $varstr;
1350
+			unset($varstr);
1351
+		} else {
1352
+			if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1353
+				if ($varstr === 'dwoo') {
1354
+					return $this->globals;
1355
+				} elseif ($varstr === '__' || $varstr === '_root' ) {
1356
+					return $this->data;
1357
+				} elseif ($varstr === '_' || $varstr === '_parent') {
1358
+					$varstr = '.'.$varstr;
1359
+					$tree = $this->scopeTree;
1360
+					$cur = $this->data;
1361
+					array_pop($tree);
1362
+
1363
+					while (($i = array_shift($tree)) !== null) {
1364
+						if (is_object($cur)) {
1365
+							$cur = $cur->$i;
1366
+						} else {
1367
+							$cur = $cur[$i];
1368
+						}
1369
+					}
1370
+
1371
+					return $cur;
1372
+				}
1373
+
1374
+				$cur = $this->scope;
1375
+
1376
+				if (isset($cur[$varstr])) {
1377
+					return $cur[$varstr];
1378
+				} else {
1379
+					return null;
1380
+				}
1381
+			}
1382
+
1383
+			if (substr($varstr, 0, 1) === '.') {
1384
+				$varstr = 'dwoo'.$varstr;
1385
+			}
1386
+
1387
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1388
+		}
1389
+
1390
+		$i = $m[2][0];
1391
+		if ($i === 'dwoo') {
1392
+			$cur = $this->globals;
1393
+			array_shift($m[2]);
1394
+			array_shift($m[1]);
1395
+			switch ($m[2][0]) {
1396
+
1397
+			case 'get':
1398
+				$cur = $_GET;
1399
+				break;
1400
+			case 'post':
1401
+				$cur = $_POST;
1402
+				break;
1403
+			case 'session':
1404
+				$cur = $_SESSION;
1405
+				break;
1406
+			case 'cookies':
1407
+			case 'cookie':
1408
+				$cur = $_COOKIE;
1409
+				break;
1410
+			case 'server':
1411
+				$cur = $_SERVER;
1412
+				break;
1413
+			case 'env':
1414
+				$cur = $_ENV;
1415
+				break;
1416
+			case 'request':
1417
+				$cur = $_REQUEST;
1418
+				break;
1419
+			case 'const':
1420
+				array_shift($m[2]);
1421
+				if (defined($m[2][0])) {
1422
+					return constant($m[2][0]);
1423
+				} else {
1424
+					return null;
1425
+				}
1426
+
1427
+			}
1428
+			if ($cur !== $this->globals) {
1429
+				array_shift($m[2]);
1430
+				array_shift($m[1]);
1431
+			}
1432
+		} elseif ($i === '__' || $i === '_root') {
1433
+			$cur = $this->data;
1434
+			array_shift($m[2]);
1435
+			array_shift($m[1]);
1436
+		} elseif ($i === '_' || $i === '_parent') {
1437
+			$tree = $this->scopeTree;
1438
+			$cur = $this->data;
1439
+
1440
+			while (true) {
1441
+				array_pop($tree);
1442
+				array_shift($m[2]);
1443
+				array_shift($m[1]);
1444
+				if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1445
+					continue;
1446
+				}
1447
+
1448
+				while (($i = array_shift($tree)) !== null) {
1449
+					if (is_object($cur)) {
1450
+						$cur = $cur->$i;
1451
+					} else {
1452
+						$cur = $cur[$i];
1453
+					}
1454
+				}
1455
+				break;
1456
+			}
1457
+		} else {
1458
+			$cur = $this->scope;
1459
+		}
1460
+
1461
+		while (list($k, $sep) = each($m[1])) {
1462
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1463
+				if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1464
+					$cur = $cur[$m[2][$k]];
1465
+				} else {
1466
+					return null;
1467
+				}
1468
+			} elseif ($sep === '->') {
1469
+				if (is_object($cur)) {
1470
+					$cur = $cur->$m[2][$k];
1471
+				} else {
1472
+					return null;
1473
+				}
1474
+			} else {
1475
+				return null;
1476
+			}
1477
+		}
1478
+
1479
+		return $cur;
1480
+	}
1481
+
1482
+	/**
1483
+	 * [runtime function] assign the value to the given variable
1484
+	 *
1485
+	 * @param mixed $value the value to assign
1486
+	 * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1487
+	 * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1488
+	 */
1489
+	public function assignInScope($value, $scope)
1490
+	{
1491
+		$tree =& $this->scopeTree;
1492
+		$data =& $this->data;
1493
+
1494
+		if (!is_string($scope)) {
1495
+			$this->triggerError('Assignments must be done into strings, ('.gettype($scope).') '.var_export($scope, true).' given', E_USER_ERROR);
1496
+		}
1497
+		if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1498
+			$this->scope[$scope] = $value;
1499
+		} else {
1500
+			// TODO handle _root/_parent scopes ?
1501
+			preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1502
+
1503
+			$cur =& $this->scope;
1504
+			$last = array(array_pop($m[1]), array_pop($m[2]));
1505
+
1506
+			while (list($k, $sep) = each($m[1])) {
1507
+				if ($sep === '.' || $sep === '[' || $sep === '') {
1508
+					if (is_array($cur) === false) {
1509
+						$cur = array();
1510
+					}
1511
+					$cur =& $cur[$m[2][$k]];
1512
+				} elseif ($sep === '->') {
1513
+					if (is_object($cur) === false) {
1514
+						$cur = new stdClass;
1515
+					}
1516
+					$cur =& $cur->$m[2][$k];
1517
+				} else {
1518
+					return false;
1519
+				}
1520
+			}
1521
+
1522
+			if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1523
+				if (is_array($cur) === false) {
1524
+					$cur = array();
1525
+				}
1526
+				$cur[$last[1]] = $value;
1527
+			} elseif ($last[0] === '->') {
1528
+				if (is_object($cur) === false) {
1529
+					$cur = new stdClass;
1530
+				}
1531
+				$cur->$last[1] = $value;
1532
+			} else {
1533
+				return false;
1534
+			}
1535
+		}
1536
+	}
1537
+
1538
+	/**
1539
+	 * [runtime function] sets the scope to the given scope string or array
1540
+	 *
1541
+	 * @param mixed $scope a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1542
+	 * @param bool $absolute if true, the scope is set from the top level scope and not from the current scope
1543
+	 * @return array the current scope tree
1544
+	 */
1545
+	public function setScope($scope, $absolute = false)
1546
+	{
1547
+		$old = $this->scopeTree;
1548
+
1549
+		if (is_string($scope)===true) {
1550
+			$scope = explode('.', $scope);
1551
+		}
1552
+
1553
+		if ($absolute===true) {
1554
+			$this->scope =& $this->data;
1555
+			$this->scopeTree = array();
1556
+		}
1557
+
1558
+		while (($bit = array_shift($scope)) !== null) {
1559
+			if ($bit === '_' || $bit === '_parent') {
1560
+				array_pop($this->scopeTree);
1561
+				$this->scope =& $this->data;
1562
+				$cnt = count($this->scopeTree);
1563
+				for ($i=0;$i<$cnt;$i++)
1564
+					$this->scope =& $this->scope[$this->scopeTree[$i]];
1565
+			} elseif ($bit === '__' || $bit === '_root') {
1566
+				$this->scope =& $this->data;
1567
+				$this->scopeTree = array();
1568
+			} elseif (isset($this->scope[$bit])) {
1569
+				if($this->scope instanceof ArrayAccess) {
1570
+					$tmp = $this->scope[$bit];
1571
+					$this->scope =& $tmp;
1572
+				} else {
1573
+					$this->scope =& $this->scope[$bit];
1574
+				}
1575
+				$this->scopeTree[] = $bit;
1576
+			} else {
1577
+				unset($this->scope);
1578
+				$this->scope = null;
1579
+			}
1580
+		}
1581
+
1582
+		return $old;
1583
+	}
1584
+
1585
+	/**
1586
+	 * [runtime function] returns the entire data array
1587
+	 *
1588
+	 * @return array
1589
+	 */
1590
+	public function getData()
1591
+	{
1592
+		return $this->data;
1593
+	}
1594
+
1595
+	/**
1596
+	 * [runtime function] sets a return value for the currently running template
1597
+	 *
1598
+	 * @param string $name var name
1599
+	 * @param mixed $value var value
1600
+	 */
1601
+	public function setReturnValue($name, $value)
1602
+	{
1603
+		$this->returnData[$name] = $value;
1604
+	}
1605
+
1606
+	/**
1607
+	 * [runtime function] retrieves the return values set by the template
1608
+	 *
1609
+	 * @return array
1610
+	 */
1611
+	public function getReturnValues()
1612
+	{
1613
+		return $this->returnData;
1614
+	}
1615
+
1616
+	/**
1617
+	 * [runtime function] returns a reference to the current scope
1618
+	 *
1619
+	 * @return &mixed
1620
+	 */
1621
+	public function &getScope()
1622
+	{
1623
+		return $this->scope;
1624
+	}
1625 1625
 
1626 1626
 	/**
1627 1627
 	 * Redirects all calls to unexisting to plugin proxy.
@@ -1630,11 +1630,11 @@  discard block
 block discarded – undo
1630 1630
 	 * @return mixed
1631 1631
 	 * @throws Dwoo_Exception
1632 1632
 	 */
1633
-    public function __call($method, $args) {
1634
-        $proxy = $this->getPluginProxy();
1635
-        if (!$proxy) {
1636
-            throw new Dwoo_Exception('Call to undefined method '.__CLASS__.'::'.$method.'()');
1637
-        }
1638
-        return call_user_func_array($proxy->getCallback($method), $args);
1639
-    }
1633
+	public function __call($method, $args) {
1634
+		$proxy = $this->getPluginProxy();
1635
+		if (!$proxy) {
1636
+			throw new Dwoo_Exception('Call to undefined method '.__CLASS__.'::'.$method.'()');
1637
+		}
1638
+		return call_user_func_array($proxy->getCallback($method), $args);
1639
+	}
1640 1640
 }
Please login to merge, or discard this patch.