- optimization of generated code for doublequoted strings containing variables

- rewrite of {function} tag handling
  - can now be declared in an external subtemplate
  - can contain nocache sections (nocache_hash handling)
  - can be called in noccache sections (nocache_hash handling)
  - new {call..} tag to call template functions with a variable name {call name=$foo}
- fixed nocache_hash handling in merged compiled templates
This commit is contained in:
Uwe.Tews
2009-12-31 16:38:12 +00:00
parent a6c4c0b192
commit 72219be200
8 changed files with 141 additions and 70 deletions

View File

@@ -1,3 +1,12 @@
12/31/2009
- optimization of generated code for doublequoted strings containing variables
- rewrite of {function} tag handling
- can now be declared in an external subtemplate
- can contain nocache sections (nocache_hash handling)
- can be called in noccache sections (nocache_hash handling)
- new {call..} tag to call template functions with a variable name {call name=$foo}
- fixed nocache_hash handling in merged compiled templates
12/30/2009 12/30/2009
- bugfix for plugins defined in the script as smarty_function_foo - bugfix for plugins defined in the script as smarty_function_foo

View File

@@ -32,32 +32,14 @@ class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase {
// output will be stored in a smarty variable instead of beind displayed // output will be stored in a smarty variable instead of beind displayed
$_assign = $_attr['assign']; $_assign = $_attr['assign'];
} }
$_name = trim($_attr['name'], "'");
// create template object
$_output = "<?php \$_template = new {$compiler->smarty->template_class} ('string:', \$_smarty_tpl->smarty, \$_smarty_tpl);\n";
$_output .= "\$_template->properties['nocache_hash'] = \$_smarty_tpl->smarty->template_functions['$_name']['nocache_hash'];\n";
// set flag (compiled code of {function} must be included in cache file // set flag (compiled code of {function} must be included in cache file
if ($this->compiler->nocache || $this->compiler->tag_nocache) { if ($this->compiler->nocache || $this->compiler->tag_nocache) {
$compiler->smarty->template_functions[$_name]['called_nocache'] = true; $nocache = 'true';
$compiler->template->properties['function'][$_name]['called_nocache'] = true; } else {
} $nocache = 'false';
// assign default paramter
if (isset($this->smarty->template_functions[$_name]['parameter'])) {
// function is already compiled
foreach ($this->smarty->template_functions[$_name]['parameter'] as $_key => $_value) {
if (!isset($_attr[$_key])) {
$_output .= "\$_template->assign('$_key',$_value);\n";
}
}
}
if (isset($compiler->template->properties['function'][$_name]['parameter'])) {
// for recursive call during function compilation
foreach ($compiler->template->properties['function'][$_name]['parameter'] as $_key => $_value) {
if (!isset($_attr[$_key])) {
$_output .= "\$_template->assign('$_key',$_value);\n";
}
}
} }
// create template object
$_output = "<?php \$_template = new Smarty_Internal_Function_Call_Handler ({$_attr['name']}, \$_smarty_tpl->smarty, \$_smarty_tpl, {$nocache});\n";
// delete {include} standard attributes // delete {include} standard attributes
unset($_attr['name'], $_attr['assign']); unset($_attr['name'], $_attr['assign']);
// remaining attributes must be assigned as smarty variable // remaining attributes must be assigned as smarty variable
@@ -67,14 +49,13 @@ class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase {
$_output .= "\$_template->assign('$_key',$_value);\n"; $_output .= "\$_template->assign('$_key',$_value);\n";
} }
} }
// load compiled function
$_output .= "\$_template->compiled_template = \$this->smarty->template_functions['$_name']['compiled'];\n\$_template->mustCompile = false;\n";
// was there an assign attribute // was there an assign attribute
if (isset($_assign)) { if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign($_assign,\$_template->getRenderedTemplate()); ?>"; $_output .= "\$_smarty_tpl->assign({$_assign},\$_template->getRenderedTemplate());\n";
} else { } else {
$_output .= "echo \$_template->getRenderedTemplate(); ?>"; $_output .= "echo \$_template->getRenderedTemplate();\n";
} }
$_output .= 'unset($_template);?>';
return $_output; return $_output;
} }
} }

View File

@@ -26,7 +26,8 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase {
$this->optional_attributes = array('_any'); $this->optional_attributes = array('_any');
// check and get attributes // check and get attributes
$_attr = $this->_get_attributes($args); $_attr = $this->_get_attributes($args);
$save = array($_attr, $compiler->template->extracted_compiled_code, $compiler->template->extract_code, $compiler->template->has_nocache_code); $save = array($_attr, $compiler->template->extracted_compiled_code, $compiler->template->extract_code,
$compiler->template->has_nocache_code, $compiler->template->required_plugins);
$this->_open_tag('function', $save); $this->_open_tag('function', $save);
$_name = trim($_attr['name'], "'"); $_name = trim($_attr['name'], "'");
unset($_attr['name']); unset($_attr['name']);
@@ -34,7 +35,9 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase {
$compiler->template->properties['function'][$_name]['parameter'][$_key] = $_data; $compiler->template->properties['function'][$_name]['parameter'][$_key] = $_data;
} }
// make function known for recursive calls // make function known for recursive calls
$this->compiler->smarty->template_functions[$_name]['compiled'] = ''; $this->compiler->smarty->template_functions[$_name]['compiled'] = '';
// Init temporay context
$compiler->template->required_plugins = array('compiled' => array(), 'cache' => array());
$compiler->template->extract_code = true; $compiler->template->extract_code = true;
$compiler->template->extracted_compiled_code = ''; $compiler->template->extracted_compiled_code = '';
$compiler->template->has_code = false; $compiler->template->has_code = false;
@@ -60,18 +63,35 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
$this->compiler->has_code = false; $this->compiler->has_code = false;
$_attr = $this->_get_attributes($args); $_attr = $this->_get_attributes($args);
$saved_data = $this->_close_tag(array('function')); $saved_data = $this->_close_tag(array('function'));
$_name = trim($saved_data[0]['name'], "'"); $_name = trim($saved_data[0]['name'], "'");
$compiler->template->properties['function'][$_name]['compiled'] = $compiler->template->extracted_compiled_code; // build plugin include code
$plugins_string = '';
if (!empty($compiler->template->required_plugins['compiled'])) {
$plugins_string = '<?php ';
foreach($compiler->template->required_plugins['compiled'] as $plugin_name => $data) {
$plugin = 'smarty_' . $data['type'] . '_' . $plugin_name;
$plugins_string .= "if (!is_callable('{$plugin}')) include '{$data['file']}';\n";
}
$plugins_string .= '?>';
}
if (!empty($compiler->template->required_plugins['cache'])) {
$plugins_string .= "<?php echo '/*%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%*/<?php ";
foreach($compiler->template->required_plugins['cache'] as $plugin_name => $data) {
$plugin = 'smarty_' . $data['type'] . '_' . $plugin_name;
$plugins_string .= "if (!is_callable(\'{$plugin}\')) include \'{$data['file']}\';\n";
}
$plugins_string .= "?>/*/%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%*/';?>\n";
}
$compiler->template->properties['function'][$_name]['compiled'] = $plugins_string . $compiler->template->extracted_compiled_code;
$compiler->template->properties['function'][$_name]['nocache_hash'] = $compiler->template->properties['nocache_hash']; $compiler->template->properties['function'][$_name]['nocache_hash'] = $compiler->template->properties['nocache_hash'];
$compiler->template->properties['function'][$_name]['has_nocache_code'] = $compiler->template->has_nocache_code; $compiler->template->properties['function'][$_name]['has_nocache_code'] = $compiler->template->has_nocache_code;
$this->compiler->smarty->template_functions[$_name]['compiled'] = $compiler->template->extracted_compiled_code; // $compiler->template->properties['function'][$_name]['plugins'] = $compiler->template->required_plugins;
$this->compiler->smarty->template_functions[$_name]['parameter'] = $compiler->template->properties['function'][$_name]['parameter']; $this->compiler->smarty->template_functions[$_name] = $compiler->template->properties['function'][$_name];
$this->compiler->smarty->template_functions[$_name]['nocache_hash'] = $compiler->template->properties['nocache_hash']; // restore old compiler status
$this->compiler->smarty->template_functions[$_name]['has_nocache_code'] = $compiler->template->has_nocache_code;
// restore old code extraction status
$compiler->template->extracted_compiled_code = $saved_data[1]; $compiler->template->extracted_compiled_code = $saved_data[1];
$compiler->template->extract_code = $saved_data[2]; $compiler->template->extract_code = $saved_data[2];
$compiler->template->has_nocache_code = $saved_data[3]; $compiler->template->has_nocache_code = $saved_data[3];
$compiler->template->required_plugins = $saved_data[4];
return true; return true;
} }
} }

View File

@@ -44,7 +44,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
// make sure that template is up to date and merge template properties // make sure that template is up to date and merge template properties
$tpl->renderTemplate(); $tpl->renderTemplate();
// compiled code for {function} tags // compiled code for {function} tags
$compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['function']); $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['function']);
// get compiled code // get compiled code
$compiled_tpl = $tpl->getCompiledTemplate(); $compiled_tpl = $tpl->getCompiledTemplate();
// remove header code // remove header code
@@ -107,7 +107,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
} }
} }
// create template object // create template object
$_output = "<?php \$_template = new {$compiler->smarty->template_class}($include_file, \$_smarty_tpl->smarty, \$_smarty_tpl, \$_smarty_tpl->cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime);"; $_output = "<?php \$_template = new {$compiler->smarty->template_class}($include_file, \$_smarty_tpl->smarty, \$_smarty_tpl, \$_smarty_tpl->cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime);\n";
// delete {include} standard attributes // delete {include} standard attributes
unset($_attr['file'], $_attr['assign'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']); unset($_attr['file'], $_attr['assign'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']);
// remaining attributes must be assigned as smarty variable // remaining attributes must be assigned as smarty variable
@@ -126,6 +126,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
$_output .= "\$_smarty_tpl->assign($_assign,\$_template->getRenderedTemplate());?>"; $_output .= "\$_smarty_tpl->assign($_assign,\$_template->getRenderedTemplate());?>";
} else { } else {
if ($has_compiled_template && !($compiler->template->caching && ($this->compiler->tag_nocache || $this->compiler->nocache))) { if ($has_compiled_template && !($compiler->template->caching && ($this->compiler->tag_nocache || $this->compiler->nocache))) {
$_output .= "\$_template->properties['nocache_hash'] = '{$compiler->template->properties['nocache_hash']}';\n";
$_output .= "\$_tpl_stack[] = \$_smarty_tpl; \$_smarty_tpl = \$_template;?>\n"; $_output .= "\$_tpl_stack[] = \$_smarty_tpl; \$_smarty_tpl = \$_template;?>\n";
$_output .= $compiled_tpl; $_output .= $compiled_tpl;
$_output .= "<?php \$_smarty_tpl->updateParentVariables($_parent_scope);?>"; $_output .= "<?php \$_smarty_tpl->updateParentVariables($_parent_scope);?>";

View File

@@ -0,0 +1,47 @@
<?php
/**
* Smarty Internal Plugin Function Call Handler
*
* @package Smarty
* @subpackage Security
* @author Uwe Tews
*/
/**
* This class does call function defined with the {function} tag
*/
class Smarty_Internal_Function_Call_Handler extends Smarty_Internal_Template {
function __construct($name, $smarty, $parent, $nocache)
{
parent::__construct('string:', $smarty, $parent);
if (!isset($this->smarty->template_functions[$name])) {
throw new Exception("Call to undefined template function \"{$name}\" in template \"{$parent->template_resource}\"");
}
$this->called_nocache = $nocache;
$this->mustCompile = false;
if ($nocache) {
$smarty->template_functions[$name]['called_nocache'] = true;
$this->properties['function'][$name]['called_nocache'] = true;
}
$this->properties['nocache_hash'] = $smarty->template_functions[$name]['nocache_hash'];
// load compiled function
if ($nocache) {
// if called in nocache mode convert nocache code to real code
$this->compiled_template = preg_replace(array("!(<\?php echo ')?/\*/?%%SmartyNocache:{$this->smarty->template_functions[$name]['nocache_hash']}%%\*/(';\?>)?!", "!\\\'!"), array('', "'"), $smarty->template_functions[$name]['compiled']);
} else {
$this->compiled_template = $smarty->template_functions[$name]['compiled'];
}
// assign default paramter
if (isset($smarty->template_functions[$name]['parameter'])) {
$_smarty_tpl = $this;
foreach ($smarty->template_functions[$name]['parameter'] as $_key => $_value) {
$this->assign($_key, eval("return {$_value};"));
}
}
// set flag if {function} contains nocache code
if ($smarty->template_functions[$name]['has_nocache_code']) {
$this->has_nocache_code = true;
}
}
}
?>

View File

@@ -484,6 +484,11 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
if ($this->smarty->debugging) { if ($this->smarty->debugging) {
Smarty_Internal_Debug::start_cache($this); Smarty_Internal_Debug::start_cache($this);
} }
// dummy renderung because of {function} nocache handling
$_smarty_tpl = $this;
ob_start();
eval("?>" . $this->rendered_content);
ob_get_clean();
// write rendered template // write rendered template
if (!$this->cacheFileWritten) { if (!$this->cacheFileWritten) {
$this->writeCachedContent($this); $this->writeCachedContent($this);
@@ -495,10 +500,11 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
Smarty_Internal_Debug::end_cache($this); Smarty_Internal_Debug::end_cache($this);
} }
} else { } else {
// var_dump('renderTemplate',$this->has_nocache_code,$this->template_resource, $this->has_nocache_code, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content); // var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) { if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
// replace nocache_hash // replace nocache_hash
$this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content); $this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
$this->parent->has_nocache_code = $this->has_nocache_code;
} }
} }
} }
@@ -780,6 +786,7 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
$this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']); $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
} }
if (!empty($properties['function'])) { if (!empty($properties['function'])) {
$this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
$this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']); $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
} }
} }

View File

@@ -117,7 +117,7 @@ class Smarty_Internal_TemplateCompilerBase {
if (($_output = $this->callTagCompiler($tag, $args)) === false) { if (($_output = $this->callTagCompiler($tag, $args)) === false) {
if (isset($this->smarty->template_functions[$tag])) { if (isset($this->smarty->template_functions[$tag])) {
// template defined by {template} tag // template defined by {template} tag
$args['name'] = $tag; $args['name'] = "'" . $tag . "'";
$_output = $this->callTagCompiler('call', $args); $_output = $this->callTagCompiler('call', $args);
} }
} }
@@ -287,29 +287,30 @@ class Smarty_Internal_TemplateCompilerBase {
foreach((array)$this->smarty->plugins_dir as $_plugin_dir) { foreach((array)$this->smarty->plugins_dir as $_plugin_dir) {
$file = rtrim($_plugin_dir, '/\\') . DS . $type . '.' . $plugin_name . '.php'; $file = rtrim($_plugin_dir, '/\\') . DS . $type . '.' . $plugin_name . '.php';
if (file_exists($file)) { if (file_exists($file)) {
require_once($file); // require_once($file);
$found = true; $found = true;
break; break;
} }
} }
if ($found) { if ($found) {
if (is_callable($plugin)) { // if (is_callable($plugin)) {
$this->template->required_plugins_call[$plugin_name][$type] = $plugin; $this->template->required_plugins_call[$plugin_name][$type] = $plugin;
if ($this->template->caching && ($this->nocache || $this->tag_nocache)) { if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
$this->template->required_plugins['cache'][$plugin_name]['file'] = $file; $this->template->required_plugins['cache'][$plugin_name]['file'] = $file;
$this->template->required_plugins['cache'][$plugin_name]['type'] = $type; $this->template->required_plugins['cache'][$plugin_name]['type'] = $type;
} else {
$this->template->required_plugins['compiled'][$plugin_name]['file'] = $file;
$this->template->required_plugins['compiled'][$plugin_name]['type'] = $type;
}
if ($type == 'modifier') {
$this->template->saved_modifer[$plugin_name] = true;
}
return $plugin;
} else { } else {
$this->template->required_plugins['compiled'][$plugin_name]['file'] = $file;
$this->template->required_plugins['compiled'][$plugin_name]['type'] = $type;
}
if ($type == 'modifier') {
$this->template->saved_modifer[$plugin_name] = true;
}
return $plugin;
/* } else {
throw new Exception("Plugin {$type} \"{$plugin_name}\" not callable"); throw new Exception("Plugin {$type} \"{$plugin_name}\" not callable");
} }
*/
} }
return false; return false;
} }

View File

@@ -1826,9 +1826,9 @@ static public $yy_action = array(
174 => 174, 174 => 174,
175 => 175, 175 => 175,
179 => 179, 179 => 179,
182 => 179, 180 => 179,
180 => 180,
181 => 181, 181 => 181,
182 => 182,
183 => 183, 183 => 183,
184 => 184, 184 => 184,
); );
@@ -2273,20 +2273,25 @@ static public $yy_action = array(
function yy_r175(){ $this->_retvalue = '\''.$this->yystack[$this->yyidx + -2]->minor.'\'=>'.$this->yystack[$this->yyidx + 0]->minor; } function yy_r175(){ $this->_retvalue = '\''.$this->yystack[$this->yyidx + -2]->minor.'\'=>'.$this->yystack[$this->yyidx + 0]->minor; }
#line 2269 "smarty_internal_templateparser.php" #line 2269 "smarty_internal_templateparser.php"
#line 515 "smarty_internal_templateparser.y" #line 515 "smarty_internal_templateparser.y"
function yy_r179(){$this->_retvalue = '".'.$this->yystack[$this->yyidx + -1]->minor.'."'; $this->compiler->has_variable_string = true; } function yy_r179(){$this->_retvalue = '{'.$this->yystack[$this->yyidx + -1]->minor.'}'; $this->compiler->has_variable_string = true; }
#line 2272 "smarty_internal_templateparser.php" #line 2272 "smarty_internal_templateparser.php"
#line 516 "smarty_internal_templateparser.y"
function yy_r180(){$this->_retvalue = '".('.$this->yystack[$this->yyidx + -1]->minor.')."'; $this->compiler->has_variable_string = true; }
#line 2275 "smarty_internal_templateparser.php"
#line 517 "smarty_internal_templateparser.y" #line 517 "smarty_internal_templateparser.y"
function yy_r181(){$this->_retvalue = '".'.'$_smarty_tpl->getVariable(\''. substr($this->yystack[$this->yyidx + 0]->minor,1) .'\')->value'.'."'; $this->compiler->tag_nocache=$this->compiler->tag_nocache|$this->template->getVariable(trim($this->yystack[$this->yyidx + 0]->minor,"'"), null, true, false)->nocache; $this->compiler->has_variable_string = true; } function yy_r181(){$this->_retvalue = '{$_smarty_tpl->getVariable(\''. substr($this->yystack[$this->yyidx + 0]->minor,1) .'\')->value}'; $this->compiler->tag_nocache=$this->compiler->tag_nocache|$this->template->getVariable(trim($this->yystack[$this->yyidx + 0]->minor,"'"), null, true, false)->nocache; $this->compiler->has_variable_string = true; }
#line 2278 "smarty_internal_templateparser.php" #line 2275 "smarty_internal_templateparser.php"
#line 519 "smarty_internal_templateparser.y" #line 518 "smarty_internal_templateparser.y"
function yy_r182(){if (substr($this->yystack[$this->yyidx + -1]->minor,0,1) == '\'') {
$this->_retvalue = '".'.$this->yystack[$this->yyidx + -1]->minor.'."'; $this->compiler->has_variable_string = true;
} else {
$this->_retvalue = '{'.$this->yystack[$this->yyidx + -1]->minor.'}'; $this->compiler->has_variable_string = true;
}
}
#line 2283 "smarty_internal_templateparser.php"
#line 524 "smarty_internal_templateparser.y"
function yy_r183(){ $this->_retvalue = '".('.$this->yystack[$this->yyidx + -1]->minor.')."'; $this->compiler->has_variable_string = true; } function yy_r183(){ $this->_retvalue = '".('.$this->yystack[$this->yyidx + -1]->minor.')."'; $this->compiler->has_variable_string = true; }
#line 2281 "smarty_internal_templateparser.php" #line 2286 "smarty_internal_templateparser.php"
#line 520 "smarty_internal_templateparser.y" #line 525 "smarty_internal_templateparser.y"
function yy_r184(){ $this->prefix_number++; $this->compiler->prefix_code[] = '<?php ob_start();?>'.$this->yystack[$this->yyidx + 0]->minor.'<?php $_tmp'.$this->prefix_number.'=ob_get_clean();?>'; $this->_retvalue = '".$_tmp'.$this->prefix_number.'."'; $this->compiler->has_variable_string = true; } function yy_r184(){ $this->prefix_number++; $this->compiler->prefix_code[] = '<?php ob_start();?>'.$this->yystack[$this->yyidx + 0]->minor.'<?php $_tmp'.$this->prefix_number.'=ob_get_clean();?>'; $this->_retvalue = '{$_tmp'.$this->prefix_number.'}'; $this->compiler->has_variable_string = true; }
#line 2284 "smarty_internal_templateparser.php" #line 2289 "smarty_internal_templateparser.php"
private $_retvalue; private $_retvalue;
@@ -2348,7 +2353,7 @@ static public $yy_action = array(
$this->internalError = true; $this->internalError = true;
$this->yymajor = $yymajor; $this->yymajor = $yymajor;
$this->compiler->trigger_template_error(); $this->compiler->trigger_template_error();
#line 2347 "smarty_internal_templateparser.php" #line 2352 "smarty_internal_templateparser.php"
} }
function yy_accept() function yy_accept()
@@ -2365,7 +2370,7 @@ static public $yy_action = array(
$this->internalError = false; $this->internalError = false;
$this->retvalue = $this->_retvalue; $this->retvalue = $this->_retvalue;
//echo $this->retvalue."\n\n"; //echo $this->retvalue."\n\n";
#line 2365 "smarty_internal_templateparser.php" #line 2370 "smarty_internal_templateparser.php"
} }
function doParse($yymajor, $yytokenvalue) function doParse($yymajor, $yytokenvalue)