diff --git a/NEWS b/NEWS
index df466fe5..a1478ccf 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,15 @@
+ - assigned variables are not longer in global
+ namespace, saving extract() calls and speeding
+ up fetch() and display() linearly with no. of
+ assigned variables (Monte)
+ - added trimwhitespace output filter to dist. (Monte)
+ - fix popup function to allow newlines in text (Monte)
- escape html entities in html_options (Monte)
- fixed bug with label for html_options (Monte)
- added caching to config file loading (Monte)
- added "extra" parameter to mailto function (Monte,
Massimiliano Perantoni)
- - added mailto function to default plugin list (Monte)
+ - added mailto plugin to dist. (Monte)
Version 2.3.1
-------------
diff --git a/Smarty.class.php b/Smarty.class.php
index 7e431124..f236f25c 100644
--- a/Smarty.class.php
+++ b/Smarty.class.php
@@ -185,7 +185,6 @@ class Smarty
array('vars' => array(), 'files' => array()));
var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; // md5 checksum of the string 'Smarty'
var $_version = '2.3.1'; // Smarty version number
- var $_extract = false; // flag for custom functions
var $_inclusion_depth = 0; // current template inclusion depth
var $_compile_id = null; // for different compiled templates
var $_smarty_debug_id = 'SMARTY_DEBUG'; // text in URL to enable debug mode
@@ -227,10 +226,11 @@ class Smarty
}
}
- if(empty($this->debug_tpl)) {
- // set path to debug template from SMARTY_DIR
- $this->debug_tpl = 'file:'.SMARTY_DIR.'debug.tpl';
- }
+ // setup debugging
+ if (!$this->debugging && $this->debugging_ctrl == 'URL'
+ && strstr($GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'], $this->_smarty_debug_id)) {
+ $this->debugging = true;
+ }
}
@@ -250,7 +250,6 @@ class Smarty
if ($tpl_var != '')
$this->_tpl_vars[$tpl_var] = $value;
}
- $this->_extract = true;
}
/*======================================================================*\
@@ -261,7 +260,6 @@ class Smarty
{
if ($tpl_var != '')
$this->_tpl_vars[$tpl_var] = &$value;
- $this->_extract = true;
}
/*======================================================================*\
@@ -287,7 +285,6 @@ class Smarty
$this->_tpl_vars[$tpl_var][] = $value;
}
}
- $this->_extract = true;
}
/*======================================================================*\
@@ -302,7 +299,6 @@ class Smarty
}
$this->_tpl_vars[$tpl_var][] = &$value;
}
- $this->_extract = true;
}
@@ -620,11 +616,6 @@ class Smarty
{
$_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(error_reporting() & ~E_NOTICE);
- if (!$this->debugging && $this->debugging_ctrl == 'URL'
- && strstr($GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'], $this->_smarty_debug_id)) {
- $this->debugging = true;
- }
-
if ($this->debugging) {
// capture time for debugging info
$debug_start_time = $this->_get_microtime();
@@ -634,11 +625,11 @@ class Smarty
$included_tpls_idx = count($this->_smarty_debug_info) - 1;
}
- if (!isset($_smarty_compile_id))
+ if (!isset($_smarty_compile_id)) {
$_smarty_compile_id = $this->compile_id;
+ }
$this->_compile_id = $_smarty_compile_id;
-
$this->_inclusion_depth = 0;
if ($this->caching) {
@@ -680,16 +671,9 @@ class Smarty
}
}
- extract($this->_tpl_vars);
-
- /* Initialize config array. */
- /*
- $this->_config = array(array('vars' => array(),
- 'files' => array()));
- */
-
- if (count($this->autoload_filters))
+ if (count($this->autoload_filters)) {
$this->_autoload_filters();
+ }
$_smarty_compile_path = $this->_get_compile_path($_smarty_tpl_file);
@@ -772,6 +756,12 @@ class Smarty
function _generate_debug_output() {
// we must force compile the debug template in case the environment
// changed between separate applications.
+
+ if(empty($this->debug_tpl)) {
+ // set path to debug template from SMARTY_DIR
+ $this->debug_tpl = 'file:'.SMARTY_DIR.'debug.tpl';
+ }
+
$_ldelim_orig = $this->left_delimiter;
$_rdelim_orig = $this->right_delimiter;
@@ -878,7 +868,7 @@ function _generate_debug_output() {
if ($resource_type == 'file') {
$readable = false;
- if(@is_file($resource_name)) {
+ if(file_exists($resource_name) && is_readable($resource_name)) {
$readable = true;
} else {
// test for file in include_path
@@ -1011,7 +1001,7 @@ function _generate_debug_output() {
// use the first directory where the file is found
foreach ((array)$file_base_path as $_curr_path) {
$_fullpath = $_curr_path . DIR_SEP . $resource_name;
- if (@is_file($_fullpath)) {
+ if (file_exists($_fullpath) && is_file($_fullpath)) {
$resource_name = $_fullpath;
return true;
}
@@ -1142,7 +1132,6 @@ function _generate_debug_output() {
}
$this->_tpl_vars = array_merge($this->_tpl_vars, $_smarty_include_vars);
- extract($this->_tpl_vars);
// config vars are treated as local, so push a copy of the
// current ones onto the front of the stack
@@ -1651,7 +1640,7 @@ function _run_insert_handler($args)
\*======================================================================*/
function _create_dir_structure($dir)
{
- if (!@file_exists($dir)) {
+ if (!file_exists($dir)) {
$_dir_parts = preg_split('!\\'.DIR_SEP.'+!', $dir, -1, PREG_SPLIT_NO_EMPTY);
$_new_dir = ($dir{0} == DIR_SEP) ? DIR_SEP : '';
@@ -1680,7 +1669,7 @@ function _run_insert_handler($args)
$_make_new_dir = true;
}
- if ($_make_new_dir && !@file_exists($_new_dir) && !@mkdir($_new_dir, 0771)) {
+ if ($_make_new_dir && !file_exists($_new_dir) && !@mkdir($_new_dir, 0771)) {
$this->trigger_error("problem creating directory \"$dir\"");
return false;
}
@@ -2078,7 +2067,7 @@ function _run_insert_handler($args)
Function: _get_include_path
Purpose: Get path to file from include_path
\*======================================================================*/
- function _get_include_path($file_path,&$new_file_path)
+ function _get_include_path($file_path, &$new_file_path)
{
static $_path_array = null;
@@ -2093,7 +2082,7 @@ function _run_insert_handler($args)
}
}
foreach ($_path_array as $_include_path) {
- if (@file_exists($_include_path . DIR_SEP . $file_path)) {
+ if (file_exists($_include_path . DIR_SEP . $file_path)) {
$new_file_path = $_include_path . DIR_SEP . $file_path;
return true;
}
diff --git a/Smarty_Compiler.class.php b/Smarty_Compiler.class.php
index f0cd8af4..fc6809f0 100644
--- a/Smarty_Compiler.class.php
+++ b/Smarty_Compiler.class.php
@@ -217,7 +217,7 @@ class Smarty_Compiler extends Smarty {
Purpose: Compile a template tag
\*======================================================================*/
function _compile_tag($template_tag)
- {
+ {
/* Matched comment. */
if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
return '';
@@ -232,12 +232,13 @@ class Smarty_Compiler extends Smarty {
/xs', $template_tag, $match);
$tag_command = $match[1];
$tag_args = isset($match[2]) ? $match[2] : '';
-
+
/* If the tag name matches a variable or section property definition,
we simply process it. */
+
if (preg_match('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) || // if a variable
preg_match('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) || // or a configuration variable
- preg_match('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)) { // or a section property
+ preg_match('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)) { // or a section property
settype($tag_command, 'array');
$this->_parse_vars_props($tag_command);
return "\n";
@@ -490,7 +491,7 @@ class Smarty_Compiler extends Smarty {
$arg_list[] = "'$arg_name' => $arg_value";
}
- return "_plugins['function']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), \$this); if(\$this->_extract) { extract(\$this->_tpl_vars); \$this->_extract=false; } ?>";
+ return "_plugins['function']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), \$this); ?>";
}
@@ -1075,12 +1076,28 @@ class Smarty_Compiler extends Smarty {
\*======================================================================*/
function _parse_vars_props(&$tokens)
{
+
$qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
$var_exprs = preg_grep('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
$conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
$sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
+ $quoted_exprs = preg_grep('!^' . $qstr_regexp . '$!', $tokens);
+ if (count($quoted_exprs)) {
+ // replace variables embedded in quotes
+ foreach ($quoted_exprs as $expr_index => $var_expr) {
+ if(preg_match_all('|(?_parse_var($var) . '."', $var_expr);
+ }
+ $tokens[$expr_index] = preg_replace(array('!^""\.!','!\.""\.!'), array('','.'), $var_expr);
+ }
+ }
+ }
+
if (count($var_exprs)) {
foreach ($var_exprs as $expr_index => $var_expr) {
$tokens[$expr_index] = $this->_parse_var($var_expr);
@@ -1096,8 +1113,9 @@ class Smarty_Compiler extends Smarty {
if (count($sect_prop_exprs)) {
foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {
$tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);
- }
+ }
}
+
}
diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php
index 7e431124..f236f25c 100644
--- a/libs/Smarty.class.php
+++ b/libs/Smarty.class.php
@@ -185,7 +185,6 @@ class Smarty
array('vars' => array(), 'files' => array()));
var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; // md5 checksum of the string 'Smarty'
var $_version = '2.3.1'; // Smarty version number
- var $_extract = false; // flag for custom functions
var $_inclusion_depth = 0; // current template inclusion depth
var $_compile_id = null; // for different compiled templates
var $_smarty_debug_id = 'SMARTY_DEBUG'; // text in URL to enable debug mode
@@ -227,10 +226,11 @@ class Smarty
}
}
- if(empty($this->debug_tpl)) {
- // set path to debug template from SMARTY_DIR
- $this->debug_tpl = 'file:'.SMARTY_DIR.'debug.tpl';
- }
+ // setup debugging
+ if (!$this->debugging && $this->debugging_ctrl == 'URL'
+ && strstr($GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'], $this->_smarty_debug_id)) {
+ $this->debugging = true;
+ }
}
@@ -250,7 +250,6 @@ class Smarty
if ($tpl_var != '')
$this->_tpl_vars[$tpl_var] = $value;
}
- $this->_extract = true;
}
/*======================================================================*\
@@ -261,7 +260,6 @@ class Smarty
{
if ($tpl_var != '')
$this->_tpl_vars[$tpl_var] = &$value;
- $this->_extract = true;
}
/*======================================================================*\
@@ -287,7 +285,6 @@ class Smarty
$this->_tpl_vars[$tpl_var][] = $value;
}
}
- $this->_extract = true;
}
/*======================================================================*\
@@ -302,7 +299,6 @@ class Smarty
}
$this->_tpl_vars[$tpl_var][] = &$value;
}
- $this->_extract = true;
}
@@ -620,11 +616,6 @@ class Smarty
{
$_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(error_reporting() & ~E_NOTICE);
- if (!$this->debugging && $this->debugging_ctrl == 'URL'
- && strstr($GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'], $this->_smarty_debug_id)) {
- $this->debugging = true;
- }
-
if ($this->debugging) {
// capture time for debugging info
$debug_start_time = $this->_get_microtime();
@@ -634,11 +625,11 @@ class Smarty
$included_tpls_idx = count($this->_smarty_debug_info) - 1;
}
- if (!isset($_smarty_compile_id))
+ if (!isset($_smarty_compile_id)) {
$_smarty_compile_id = $this->compile_id;
+ }
$this->_compile_id = $_smarty_compile_id;
-
$this->_inclusion_depth = 0;
if ($this->caching) {
@@ -680,16 +671,9 @@ class Smarty
}
}
- extract($this->_tpl_vars);
-
- /* Initialize config array. */
- /*
- $this->_config = array(array('vars' => array(),
- 'files' => array()));
- */
-
- if (count($this->autoload_filters))
+ if (count($this->autoload_filters)) {
$this->_autoload_filters();
+ }
$_smarty_compile_path = $this->_get_compile_path($_smarty_tpl_file);
@@ -772,6 +756,12 @@ class Smarty
function _generate_debug_output() {
// we must force compile the debug template in case the environment
// changed between separate applications.
+
+ if(empty($this->debug_tpl)) {
+ // set path to debug template from SMARTY_DIR
+ $this->debug_tpl = 'file:'.SMARTY_DIR.'debug.tpl';
+ }
+
$_ldelim_orig = $this->left_delimiter;
$_rdelim_orig = $this->right_delimiter;
@@ -878,7 +868,7 @@ function _generate_debug_output() {
if ($resource_type == 'file') {
$readable = false;
- if(@is_file($resource_name)) {
+ if(file_exists($resource_name) && is_readable($resource_name)) {
$readable = true;
} else {
// test for file in include_path
@@ -1011,7 +1001,7 @@ function _generate_debug_output() {
// use the first directory where the file is found
foreach ((array)$file_base_path as $_curr_path) {
$_fullpath = $_curr_path . DIR_SEP . $resource_name;
- if (@is_file($_fullpath)) {
+ if (file_exists($_fullpath) && is_file($_fullpath)) {
$resource_name = $_fullpath;
return true;
}
@@ -1142,7 +1132,6 @@ function _generate_debug_output() {
}
$this->_tpl_vars = array_merge($this->_tpl_vars, $_smarty_include_vars);
- extract($this->_tpl_vars);
// config vars are treated as local, so push a copy of the
// current ones onto the front of the stack
@@ -1651,7 +1640,7 @@ function _run_insert_handler($args)
\*======================================================================*/
function _create_dir_structure($dir)
{
- if (!@file_exists($dir)) {
+ if (!file_exists($dir)) {
$_dir_parts = preg_split('!\\'.DIR_SEP.'+!', $dir, -1, PREG_SPLIT_NO_EMPTY);
$_new_dir = ($dir{0} == DIR_SEP) ? DIR_SEP : '';
@@ -1680,7 +1669,7 @@ function _run_insert_handler($args)
$_make_new_dir = true;
}
- if ($_make_new_dir && !@file_exists($_new_dir) && !@mkdir($_new_dir, 0771)) {
+ if ($_make_new_dir && !file_exists($_new_dir) && !@mkdir($_new_dir, 0771)) {
$this->trigger_error("problem creating directory \"$dir\"");
return false;
}
@@ -2078,7 +2067,7 @@ function _run_insert_handler($args)
Function: _get_include_path
Purpose: Get path to file from include_path
\*======================================================================*/
- function _get_include_path($file_path,&$new_file_path)
+ function _get_include_path($file_path, &$new_file_path)
{
static $_path_array = null;
@@ -2093,7 +2082,7 @@ function _run_insert_handler($args)
}
}
foreach ($_path_array as $_include_path) {
- if (@file_exists($_include_path . DIR_SEP . $file_path)) {
+ if (file_exists($_include_path . DIR_SEP . $file_path)) {
$new_file_path = $_include_path . DIR_SEP . $file_path;
return true;
}
diff --git a/libs/Smarty_Compiler.class.php b/libs/Smarty_Compiler.class.php
index f0cd8af4..fc6809f0 100644
--- a/libs/Smarty_Compiler.class.php
+++ b/libs/Smarty_Compiler.class.php
@@ -217,7 +217,7 @@ class Smarty_Compiler extends Smarty {
Purpose: Compile a template tag
\*======================================================================*/
function _compile_tag($template_tag)
- {
+ {
/* Matched comment. */
if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
return '';
@@ -232,12 +232,13 @@ class Smarty_Compiler extends Smarty {
/xs', $template_tag, $match);
$tag_command = $match[1];
$tag_args = isset($match[2]) ? $match[2] : '';
-
+
/* If the tag name matches a variable or section property definition,
we simply process it. */
+
if (preg_match('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) || // if a variable
preg_match('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) || // or a configuration variable
- preg_match('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)) { // or a section property
+ preg_match('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)) { // or a section property
settype($tag_command, 'array');
$this->_parse_vars_props($tag_command);
return "\n";
@@ -490,7 +491,7 @@ class Smarty_Compiler extends Smarty {
$arg_list[] = "'$arg_name' => $arg_value";
}
- return "_plugins['function']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), \$this); if(\$this->_extract) { extract(\$this->_tpl_vars); \$this->_extract=false; } ?>";
+ return "_plugins['function']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), \$this); ?>";
}
@@ -1075,12 +1076,28 @@ class Smarty_Compiler extends Smarty {
\*======================================================================*/
function _parse_vars_props(&$tokens)
{
+
$qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
$var_exprs = preg_grep('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
$conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
$sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
+ $quoted_exprs = preg_grep('!^' . $qstr_regexp . '$!', $tokens);
+ if (count($quoted_exprs)) {
+ // replace variables embedded in quotes
+ foreach ($quoted_exprs as $expr_index => $var_expr) {
+ if(preg_match_all('|(?_parse_var($var) . '."', $var_expr);
+ }
+ $tokens[$expr_index] = preg_replace(array('!^""\.!','!\.""\.!'), array('','.'), $var_expr);
+ }
+ }
+ }
+
if (count($var_exprs)) {
foreach ($var_exprs as $expr_index => $var_expr) {
$tokens[$expr_index] = $this->_parse_var($var_expr);
@@ -1096,8 +1113,9 @@ class Smarty_Compiler extends Smarty {
if (count($sect_prop_exprs)) {
foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {
$tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);
- }
+ }
}
+
}
diff --git a/libs/plugins/outputfilter.trimwhitespace.php b/libs/plugins/outputfilter.trimwhitespace.php
new file mode 100644
index 00000000..49f4072e
--- /dev/null
+++ b/libs/plugins/outputfilter.trimwhitespace.php
@@ -0,0 +1,49 @@
+ and blocks.
+ * Install: Drop into the plugin directory, call
+ * $smarty->load_filter('output','trimwhitespace');
+ * from application.
+ * Author: Monte Ohrt
+ * -------------------------------------------------------------
+ */
+ function smarty_outputfilter_trimwhitespace($source, &$smarty)
+ {
+ // Pull out the script blocks
+ preg_match_all("!!is", $source, $match);
+ $_script_blocks = $match[0];
+ $source = preg_replace("!!is",
+ '@@@SMARTY:TRIM:SCRIPT@@@', $source);
+
+ // Pull out the pre blocks
+ preg_match_all("!.*?
!is", $source, $match);
+ $_pre_blocks = $match[0];
+ $source = preg_replace("!.*?
!is",
+ '@@@SMARTY:TRIM:PRE@@@', $source);
+
+ // remove all leading spaces, tabs and carriage returns NOT
+ // preceeded by a php close tag.
+ $source = preg_replace('/((?)\n)[\s]+/m', '\1', $source);
+
+ // replace script blocks
+ foreach($_script_blocks as $curr_block) {
+ $source = preg_replace("!@@@SMARTY:TRIM:SCRIPT@@@!",$curr_block,$source,1);
+ }
+ // replace pre blocks
+ foreach($_pre_blocks as $curr_block) {
+ $source = preg_replace("!@@@SMARTY:TRIM:PRE@@@!",$curr_block,$source,1);
+ }
+
+ return $source;
+ }
+?>
diff --git a/plugins/outputfilter.trimwhitespace.php b/plugins/outputfilter.trimwhitespace.php
new file mode 100644
index 00000000..49f4072e
--- /dev/null
+++ b/plugins/outputfilter.trimwhitespace.php
@@ -0,0 +1,49 @@
+ and blocks.
+ * Install: Drop into the plugin directory, call
+ * $smarty->load_filter('output','trimwhitespace');
+ * from application.
+ * Author: Monte Ohrt
+ * -------------------------------------------------------------
+ */
+ function smarty_outputfilter_trimwhitespace($source, &$smarty)
+ {
+ // Pull out the script blocks
+ preg_match_all("!!is", $source, $match);
+ $_script_blocks = $match[0];
+ $source = preg_replace("!!is",
+ '@@@SMARTY:TRIM:SCRIPT@@@', $source);
+
+ // Pull out the pre blocks
+ preg_match_all("!.*?
!is", $source, $match);
+ $_pre_blocks = $match[0];
+ $source = preg_replace("!.*?
!is",
+ '@@@SMARTY:TRIM:PRE@@@', $source);
+
+ // remove all leading spaces, tabs and carriage returns NOT
+ // preceeded by a php close tag.
+ $source = preg_replace('/((?)\n)[\s]+/m', '\1', $source);
+
+ // replace script blocks
+ foreach($_script_blocks as $curr_block) {
+ $source = preg_replace("!@@@SMARTY:TRIM:SCRIPT@@@!",$curr_block,$source,1);
+ }
+ // replace pre blocks
+ foreach($_pre_blocks as $curr_block) {
+ $source = preg_replace("!@@@SMARTY:TRIM:PRE@@@!",$curr_block,$source,1);
+ }
+
+ return $source;
+ }
+?>