Location: PHPKode > projects > BoltWire > barn/scripts/functions.php
<?php if (!defined('BOLTWIRE')) exit();

########################################
##  BOLTWIRE FUNCTIONS                ##
##  Copyright 2010 Dan Vis            ##
##  See license.txt for details       ##
########################################

## THE FIRST FUNCTION HANDLE PARSES PARAMETERS, CHECKS MAPPING, RETURNS RESULT
## THE FOLLOWING SPECIFIC FUNCTIONS CAN BE FOUND BELOW IN ALPHABETICAL ORDER:
## BREADCRUMB, COUNTER, DIFF, FIND, FORWARD, GETLINK, INCLUDE, INDEX, INFO, LASTMODIFIED
## LIST, LOG, MAIL, MEMBERSHIPS, NOCACHE, OVERWRITE, PREVIEW, RANDOM, SCRIPT, SEARCH
## SOURCE, TIME, TOC, TOUCH, TRANSLATE, ZONES


function BOLTFbreadcrumb($args, $zone='') {
## TAKES A PAGE NAME AND BREAKS IT DOWN TO A DISPLAY OF CLICKABLE LINKS UP IT'S HIERARCHY. PAGE NAME USED DEFAULTS TO CURRENT PAGE, BUT CAN BE RESET BY PARAMETER PAGE OR #1. OTHER OPTIONAL PARAMETERS INCLUDE SEPARATOR (DEFAULT >) AND NAME=LINK/NONE (DEFAULT TEXT) TO DEFINE HOW LAST PAGE PART IS DISPLAYED. SET TEXT=TRUE TO DEACTIVATE LINKS. SET MISSING=LINK,MARK,NONE OR TEXT (DEFAULT). USE OFFSET=1 TO IGNORE FIRST PAGE PART. USE RTL=TRUE FOR RIGHT-TO-LEFT DISPLAY
	global $pageLink;
	if (isset($args['page'])) $page = $args['page'];
	elseif (isset($args[1])) $page = $args[1];
	else $page = $pageLink;
	$page = BOLTfilter(BOLTpageshortcuts($page), 'page');
	$separator = isset($args['separator']) ? $args['separator'] : ' > ';
	$parts = explode('.', $page);
	if ($args['missing'] != 'mark') $missing = '?';
	foreach ($parts as $p) {
		$link = ltrim("$link.$p", '.');
		if ($args['text'] == 'true') $out[] = BOLTvars("$link:title");
		else {
			if (! BOLTexists($link)) {
				if ($args['missing'] == 'mark' || $args['missing'] == 'link') $out[] = "[[$missing$link|+]]";
				elseif($args['missing'] != 'none') $out[] = ucfirst($p);
				}
			else $out[] = "[[$missing$link|+]]";
			}
		}
	switch ($args['name']) {
		case 'none': unset($out[count($parts) - 1]); break;
		case 'page': $out[count($parts) - 1] = ucfirst($p); break;
		case 'link': break;
		default: $out[count($parts) - 1] = BOLTvars("$page:title"); break;
		}
	if (isset($args['offset'])) $out = array_slice($out, $args['offset']);
	if (strtolower($args['rtl']) == 'true' || strtolower(BOLTconfig('BOLTtextDirection')) == 'rtl') {
	 	$out = array_reverse($out);
		$separator = str_replace('>', '<', $separator);
		}
	$out = implode($separator, $out);
	return "<nolines>$out</nolines>";
	}

function BOLTFcounter($args, $zone='') {
## A COMPLEX MATHEMATICAL FUNCTION WITH MANY OPTIONS, DEFAULTS TO ADDING +1 TO A NUMBER IN #1. BUT CAN HANDLE A SIMPLE MATHEMATICAL STRINGS. CAN ALSO SET A DIFFERENT INCREMENT IN #2. CAN SET #1 TO + OR -. CAN SET DECIMAL TO NUMBER OF ALLOWED PLACES. SAVES VALUES IN A $BOLTcounter VARIABLE FOR USE IN COMPLEX TEMPLATES, USING AN ID PARAMETER. PROBABLY SHOULD RENAME TO MATH OR SOMETHING.
	global $BOLTcounter;
	if (isset($args['id'])) $id = $args['id'];
	else $id = 0;
	if ($args[2] != '') $increment = $args[2];
	else $increment = 1;
	if (! isset($args[1])) $args[1] = '+';
	if ($args[1] == '+') $BOLTcounter[$id] = $BOLTcounter[$id] + $increment;
	elseif ($args[1] == '-') $BOLTcounter[$id] = $BOLTcounter[$id] - $increment;
	elseif (is_numeric($args[1])) $BOLTcounter[$id] = $args[1];
	elseif ($args[1] != '' && $args[1] != '=') {
		$value = $args[1];
		if (BOLTfilter($value, '-+0-9/*.() ') != '') eval("\$BOLTcounter[\$id] = $value;");
		}
	$out = $BOLTcounter[$id];
	if (isset($args['decimal']) && strpos($out, '.') !== false) $out = rtrim(substr($out, 0, strpos($out, '.') + $args['decimal'] + 1), '.');
	if ($args['output'] == 'true') return $out;
	}

function BOLTFdiff($args, $zone='', $escape=true, $save='') {
## USED TO GENERATE A DIFF BETWEEN A STAMPED VERSION AND THE CURRENT VERSION OF A PAGE (OR 2 STAMPS). MOSTLY USED IN THE ACTION.HISTORY PAGE TO GENERATE A REPORT OF CHANGES. MOST OF THE WORK ACTUALLY DONE IN THE SYSTEM FUNCTION BOLTdiff
	global $pageLink, $pagesDir, $BOLTdiffCount;
	if (isset($args[2])) return BOLTdiff(BOLTloadpage($args[1]), BOLTloadpage($args[2]));
	if (isset($args[1])) $n = $args[1];
	else $n = $pageLink;
	$new = BOLTloadpage($n);
	$dir = BOLTconfig('BOLTstampsDir', 'stamps');
	$pages = BOLTlistpages("/^$n\\.\\d/", $dir);
	$old = BOLTloadpage($pages[count($pages)-1], $dir);
	$out = BOLTdiff($old, $new);
	if ($save == true) $out = str_replace(Array('&lt;', '&gt;', '&amp;'), Array('<', '>', '&'), $out);
	else $out = str_replace(Array('&lt;span class=diff&gt;', '&lt;/span&gt;', '&lt;br /&gt;', "\n", '[fo>rm'), Array('<span class=diff>', '</span>', '<br />', '<br />', '[form'), htmlspecialchars($out, ENT_NOQUOTES));
	if (BOLTconfig('BOLTstampMode') == 'html' || $escape == false) return $out;
	return BOLTescape(str_replace("\n", '<br />', $out), true);
	}

function BOLTFfind($args, $zone='') {
## FUNCTION FOR SCANNING ACTUAL PAGES FOR CONTENT. MANY POSSIBLE PARAMETERS. LIMIT PAGES BY PAGES, PATTERN, GROUP, INCLUDE, EXCLUDE, TYPE, FOLDER, DIR. SEARCH STRING,MARKUP,REGEX. ORGANIZE BY SORT,IF. OUTPUT IS TEMPLATE OR FMT
	$pages = BOLTsearchPageList($args);
	if (count($pages) < 1) return BOLTdisplay(Array(), $args, $zone);
	if ($args['data'] == 'true') $data = 'data';
	if (isset($args['string'])) {
		if ($args['case'] !== 'true') $args['string'] = strtolower($args['string']);
		foreach ($pages as $page) {
			$content = BOLTloadpage($page, '', $data, true);
			if ($args['case'] !== 'true') $content = strtolower($content);
			if (strpos($content, $args['string']) !== false) $outarray[] = $page;
			}
		}
	else {
		if (isset($args['markup'])) {
			global $MarkUpTable;
			$pattern = explode(':', $args['markup']);
			$args['regex'] = $MarkUpTable[$pattern[0]][$pattern[1]]['pattern'];
			if ($args['regex'] == '') return "Markup rule not found.";
			}
		foreach ($pages as $page) {
			$content = BOLTloadpage($page, '', $data, true);
			if (preg_match($args['regex'], $content) !== 0) $outarray[] = $page;
			}
		}
	if (! is_array($outarray)) $outarray = Array();
	return BOLTdisplay($outarray, $args, $zone);
	}

function BOLTFforward($args, $zone='') {
## TAKES A PAGE NAME AND FORWARDS BROWSER AUTOMATICALLY, USE <( )> SYNTAX TO FORWARD ON CONDITIONS. DOES NOT WORK IF ACTION IS SOMETHING BESIDE PRINT OR EDIT. SET URL= TO FORWARD TO AN EXTERNAL LINK
	global $BOLTvar, $pageLink;
	if (isset($args['url'])) {
		header("Location: http://" . $args['url']);
		header("Content-type: text/html");
		print_r("<html><head><meta http-equiv=Refresh></head><body></body></html>");
		exit;
		}
	if ($pageLink == $args[1] && ! isset($BOLTvar['$action'])) return;
	BOLTmsg('func_forward', "~$pageLink~$args[1]", $args);
	BOLTredirect($args[1]);
	}

function BOLTFgetlink($args, $zone='') {
## A FUNCTION TO TAP INTO THE HIEARCHICAL PAGE SYSTEM. FOR EXAMPLE GETLINK SIDE WILL FIND THE CLOSEST SIDE PAGE TO THE CURRENT PAGE
	$link = BOLTfilter($args[1], 'page');
	if (strpos(',' . BOLTFzones(Array('1'=>'code')) . ',', ",$link,") !== false && $link != '') $pre = 'code';
	$hlink = BOLTgetlink($pre, $link);
	if ($hlink == '') return $link;
	return $hlink;
	}

function BOLTFhelp($args, $zone='') {
## A BUILT IN HELP SYSTEM FOR BOLTWIRE FUNCTIONS. TO USE ADD &help=topic TO ANY URL. THE OUTPUT IS INSERTED INTO THE MAIN ZONE. OPTIONS INCLUDE PLUGINS=TRUE TO ALSO SCAN PLUGINS AND SCRIPT=FILE TO ONLY LOAD FILE.PHP
	global $BOLTscripts, $BOLTplugins, $scriptPath, $pluginPath, $scriptURL, $pageLink;
	if (isset($_GET['help'])) $args['help'] = $_GET['help'];
	if (isset($_GET['script'])) $args['script'] = $_GET['script'];
	if (isset($_GET['code'])) $args['code'] = $_GET['code'];
	if ($args['help'] == '') $args['help'] = $args[1];
	if ($args['help'] == '') return;
	if (strtolower($args['help']) == 'markuptable' || (strtolower($args['help']) == 'initialization')) {
		if (strtolower($args['help']) == 'markuptable') $file = 'markups.php';
		else $file = 'engine.php';
		$code = file_get_contents("$scriptPath/$file");
		$code = substr($code, strpos($code, "\n## " . strtoupper($args['help'])));
		$code = substr($code, 0, strpos($code, "\n## END " . strtoupper($args['help'])));
		$code = str_replace(Array('<', "\n", "\t"), Array('&lt;', "<br/>","&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"), trim($code));
		return BOLTescape("<br /><table border=1 width=100%><tr><td>$code</td></tr></table>");
		}
	if (isset($args['script'])) $scripts = Array($args['script']);
	else $scripts = array_merge(Array('engine'), $BOLTscripts, Array('commands'));
	if (strtolower($args['help']) == 'all') $args['help'] = '';
	if (isset($args['func'])) $which = $args['func'];
	else $which = $args['help'];
	foreach ($scripts as $i => $ii) {
		if (file_exists("$scriptPath/$ii.php")) $code =  file_get_contents("$scriptPath/$ii.php");
		elseif (file_exists("$pluginPath/$ii.php")) $code =  file_get_contents("$pluginPath/$ii.php");
		$pat = '/\n(function ([a-zA-Z]*)'.$which.'([^\t]+))/si';
		preg_match_all($pat, $code, $matches);
		foreach ($matches[1] as $func) {
			$pos_name = strpos($func, '(');
			$pos_close = strpos($func, ')');
			$pos_notes = strpos($func, "\n");
			$help['function'] = trim(substr($func, 8, $pos_name - 8));
			$help['script'] = $ii;
			switch(substr($help['function'], 0, 5)) {
				case 'BOLTC' : $help['type'] = 'Conditional'; break;
				case 'BOLTF' : $help['type'] = 'Available Function'; break;
				case 'BOLTX' : $help['type'] = 'Form Command'; break;
				case 'BOLTM' : $help['type'] = 'Markup Processor'; break;
				default : $help['type'] = 'System Function';
				}
			$help['args'] = trim(substr($func, $pos_name + 1, $pos_close - $pos_name - 1));
			$help['notes'] = str_replace(Array("\n", '##'), Array('<br/>', ''), trim(substr($func, $pos_notes)));
			if ($args['code'] != 'true') $help['link'] = "<a href='$scriptURL$pageLink&help=$help[function]&script=$help[script]&code=true'>Show Code</a>";
			else {
				$fullcode = substr($code, strpos($code, $func) + 8);
				$fullcode = 'function ' . trim(substr($fullcode, 0, strpos("$fullcode\nfunction", "\n\t}") + 3));
				$fullcode = str_replace(Array('<', "\n", "\t"), Array('&lt;', "<br/>","&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"), $fullcode);
				$fullcode = "<tr><td colspan=2>$fullcode</td></tr>";
				$help['link'] = "<a href='$scriptURL$pageLink&help=$help[function]&script=$help[script]'>Hide Code</a>";
				}
			$out[] = "<table border=1 width=100%><tr><td>Name:</td><td width=90%>$help[function]</td></tr><tr><td>Type:</td><td>$help[type]</td></tr><tr><td>Args:</td><td>$help[args]</td></tr><tr><td valign='top'>Notes:</td><td>$help[notes]</td></tr><tr><td>Script:</td><td>$help[script].php</td></tr><tr><td>Code:</td><td>$help[link]</td></tr>$fullcode</table><br />";

			}
		}
	if (is_array($out)) return BOLTescape(implode("\n\n", $out));
	return BOLTescape("No HELP information found on <b>$args[help]</b>.");
	}

function BOLTFinclude($args, $zone='') {
## INCLUDE CONTENT FROM ANOTHER PAGE. MARKUP IS PROCESSED AND ESCAPED. MANY PARAMETERS INCLUDING: PAGE(#1). USE PAGE=SIDE* FOR HIERARCHICAL LINK. PAGE SHORTCUTS CAN BE USED. ANCHORS CAN BE USED TO RETRIEVES SECTIONS (PAGE#SECTION). CAN RETRIEVE LINES=5 OR LINES=5..10. DIR CAN BE SET TO SYSTEM OR STAMPS. SET HEADER/FOOTER TRUE TO RETRIEVE THOSE AS WELL. SOME OTHER ADVANCED PARAMETERS INCLUDE BASELINKS, BASEPAGE(?), REPLACE=FALSE, OUTPUT=TRIM. PROBABLY SHOULD ADD AN ESCAPE=FALSE OPTION. FAILS IF "[(INCLUDE" IS ON TARGET PAGE TO PREVENT INFINITE LOOP
	global $pageLink, $BOLTid, $systemPath, $BOLTincludedPages;
	$BOLTstampsDir = BOLTconfig('BOLTstampsDir', 'stamps');
	if (isset($args['page'])) $page = $args['page'];
	else $page = $args[1];
	if (strpos($page, ':') !== false) {
		$data = substr($page, strpos($page, ':'));
		$page = substr($page, 0, strpos($page, ':'));
		}
	if (strpos($page, '#') !== false) {
		$anchor = substr($page, strpos($page, '#'));
		$page = substr($page, 0, strpos($page, '#'));
		}
	$page = BOLTpageshortcuts($page);
	if (BOLTfilter($page, 'page') == '') return;
	if ($BOLTincludedPages[$page] === true) return;
	else $BOLTincludedPages[$page] = true;
	if (substr($page, 0, 1) == '*') $page = BOLTgetlink('', substr($page, 1));
	if (BOLTauth($page, $BOLTid, 'view') === false) return BOLTmsg('func_include_auth', "~$page", $args);
	$dir = '';
	if ($args['dir'] == 'system') $dir = $systemPath;
	if ($args['dir'] == 'stamps') $dir = $BOLTstampsDir;
	if ($data != '') $out = BOLTvars("$page$data");
	else {
		$out = BOLTloadpage("$page$anchor", $dir);
		if (isset($args['lines'])) $out = BOLTgetlines($out, $args['lines']);
		}
	$tempArray = explode(".", $page);
	if ($args['header'] == 'true') {
		$header = BOLTloadpage(BOLTgetlink('', 'header', $tempArray));
		$out = $header . $out;
		}
	if ($args['footer'] == 'true') {
		$footer = BOLTloadpage(BOLTgetlink('', 'footer', $tempArray));
		$out =  $out . $footer;
		}
//	if ($args['baselinks'] == 'true') $out = str_replace('{', '{+', $out);
	if ($args['replace'] == 'true') $replace = true;
	if ($args['output'] == 'trim') $out = trim($out);
	if ($args['basepage'] == 'true') {
		$temp = $pageLink;
		$pageLink = $page;
		if ($args['replace'] != 'false') $replace = true;
		$out = BOLTescape(BOLTdomarkup($out, $page, $zone, '', $replace));
		$pageLink = $temp;
		}
	else $out = BOLTescape(BOLTdomarkup($out, $page, strtoupper($zone), $args['rules'], $replace));
	if (strpos($out, '(include') === false) $BOLTincludedPages[$page] = false;
	BOLTmsg('func_include', "~$page", $args);
	return $out;
	}

function BOLTFindex($args, $zone='') {
## THIS IS THE MAIN FUNCTION FOR ACCESSING THE INDEX FUNCTION.
	return BOLTindex($args, $zone);
	}

function BOLTFinfo($args, $zone='', $auth=true) {
## THE INFO FUNCTION CAN READ, WRITE, AND PROCESS INFO VARS IN MANY WAYS. CAN BE EXTENDED. MANY PARAMETERS INCLUDING FIELD, VALUE, TARGET. SET EXCLUDE TO DO NOTHING ON CERTAIN PAGES (HEADER/FOOTER, FOR EXAMPLE). I THINK CAN PUT A +VALUE,-VALUE CSV LIST IN VALUE AND WILL HANDLE PROPERLY. TARGET DEFAULTS TO CURRENT PAGE. IF JUST FIELD SET RETURNS VALUE. IF FIELD AND VALUE, RESETS VALUE (ASSUMING INFO AUTHORIZATION). IF #1 IS A RECOGNIZED KEY WORD (IE FUNCTION EXISTS BOLTinfoKeyWord()) INFO RUNS THAT EXTENSION. SYSTEM EXTENSIONS INCLUDES DELETE (VALUE), COUNT (ENTRIES WITH "BASE" FIELD), SUM (ENTRIE VALUES WITH "BASE" FIELD), LIST (INFO VARS ON PAGE?), COUNTER (ADDS 1 TO FIELD). NEEDS VIEW AUTHORIZATION TO READ, INFO AUTHORIZATION TO WRITE
	global $pageLink, $pagesDir, $BOLTpagecount, $BOLTid, $BOLTinfoVarPat;
	if (isset($args['field'])) $field = trim(BOLTurl2utf($args['field']));
	else $field = BOLTurl2utf($pageLink);
	$field = str_replace(' ', '_', $field);
	if (isset($args['exclude']) && strpos(",$args[exclude],", ",$pageLink,") !== false) return; // used to not count header/footer pages for example.
	if (isset($args['target'])) $target = BOLTpageshortcuts($args['target']);
	else $target = $pageLink;
	if (BOLTauth($target, $BOLTid, 'view') === false) return;
	$content = BOLTloadpage($target);
	$value = trim($args['value']);
	if ($args['pattern'] == '') {
		if ($BOLTinfoVarPat == '') $pattern = '/^(\S+)\: (.+)?/m';
		else $pattern = $BOLTinfoVarPat;
		}
	else $pattern = $args['pattern'];
	$current = BOLTinfoVar($target, $field, '', false, $pattern);
	if (substr($value, 0, 1) == "+" || substr($value, 0, 1) == "-") $value = BOLTcsv($value, $current);
	if ($args[1] == '') {
		if ($field == '') return;
		if ($value == '') return $current;
		if (BOLTauth($target, $BOLTid, 'info') === false && BOLTauth($target, $BOLTid, 'write') === false) return BOLTmsg('func_info_auth', "~$target.", $args);
		if ($args['pattern'] != '') {
			preg_match_all($pattern, $content, $matches);
			$i = array_search($field, $matches[1]);
			$newvalue = str_replace($current, $value, $matches[0][$i]);
			$content = str_replace($matches[0][$i], $newvalue, $content);
			}
		else {
			if (strpos("\n$content", "\n$field: ") === false) $content = $content . "\n$field: $value";
			else $content = substr(str_replace("\n$field: $current", "\n$field: $value", "\n$content"), 1);
			}
//		$content = str_replace('&lt;', '<', $content);
		BOLTsavepage($target, $content, '', false, false);	
		return;
		}
	preg_match_all($pattern, $content, $matches);
	if (count($matches[1]) != 0) {
		foreach($matches[1] as $i => $ii) $info[$ii] = $matches[2][$i];
		foreach ($info as $i => $ii) {
			$x = $x + 1;
			$info_flip["$ii<$x"] = $i;
			}
		$info = Array();
		if (isset($args['if'])) $args['if'] = str_replace(Array('{+field}', '{+value}'), Array('{+p}', '{'.$target.'::{+p}}'), $args['if']);
		if (isset($args['sort']) && $args['sort'] != 'false') { $infosort = $args['sort']; unset($args['sort']); }
		$infoorder = $args['order']; unset($args['order']);
		$info_flip = BOLTsearchPageListPlus($info_flip, $args);
		if (count($info_flip) != 0) {
			if (isset($args['base'])) {
				foreach($info_flip as $i => $ii) {
					if (substr($ii, 0, strlen($args['base'])) != $args['base']) unset($info_flip[$i]);
					}
				}
			if (count($info_flip) != 0) {
				if ($infosort == 'field') natsort($info_flip);
				elseif ($infosort == 'value') uksort($info_flip, "strnatcmp");
				else $args['sort'] = $infosort;
				$args['order'] = $infoorder;
				$info_flip = BOLTsort($info_flip, $args);

				foreach ($info_flip as $i => $ii) $info[$ii] = substr($i, 0, strrpos($i, '<'));
				}
			}
		}
	else $info = Array();
	$func = "BOLTinfo" . $args[1];
	if (function_exists($func)) return $func($info, $args, $target);
	switch($args[1]) {
		case 'delete' :
			if ($auth && BOLTauth($target, $BOLTid, 'info') === false) return;
			if ($args['pattern'] != '') {
				preg_match_all($pattern, $content, $matches);
				$i = array_search($field, $matches[1]);
				$content = str_replace("\n".$matches[0][$i], '', $content);
				}
			else $content = substr(str_replace("\n$field: $current", '', "\n$content"), 1);
			if ($content == '') $content = ' ';
			BOLTsavepage($target, $content, '', false, false);	
			return;
		case 'count' :
			foreach ($info as $i => $ii) $c = $c + 1;
			return $c;
		case 'sum' :			
			foreach ($info as $i => $ii) $c = $c + $ii;
			return $c;
		case 'find':
			return array_search($value, $info);
		case 'inlist':
			foreach ($info as $f => $v) {
				if (strpos(",$v,", ",$value") !== false) return $f;
				}
			return;
		case 'next' :
			if (BOLTauth($target, $BOLTid, 'info') === false && BOLTauth($target, $BOLTid, 'write') === false) return 'Not authorized...';
			if ($args['unique'] == 'true' && array_search($value, $info)) return 'Value already exists';
			$info[] = $value;
			foreach ($info as $f => $v) $out .= "$f: $v\n";
			BOLTsavepage($target, $out, '', false, false);
			return $f;
		case 'report' :
			$args['template'] = str_replace(Array('{+field}', '{+value}'), Array('{+p}', '{+index}'), $args['template']);
			$args['fmt'] = str_replace(Array('{+field}', '{+value}'), Array('{+p}', '{+index}'), $args['fmt']);
			if (count($info_flip) == 0) return BOLTdisplay(Array(), $args, $zone);
			return BOLTdisplay($info_flip, $args, $zone);
		case 'counter' :
			if (BOLTauth($target, $BOLTid, 'info') === false) return;
			$counter = $current + 1;
			if (strpos("\n$content", "\n$field: ") === false) $content = $content . "\n$field: $counter";
			else $content = substr(str_replace("\n$field: $current", "\n$field: $counter", "\n$content"), 1);
			BOLTsavepage($target, $content, '', false, false);	
			return $counter;
		}
	}

function BOLTFlastmodified($args, $zone='') {
## RETURNS THE LAST MODIFIED DATE OF A PAGE(#1), IN STRFTIME FMT(#2). CAN SET DIR TO PLUGINS, SYSTEM, PAGES(?)
	global $pagesDir, $pageLink, $pluginPath, $systemPath;
	if ($args['page'] != '') $page = $args['page'];
	else $page = $args[1];
	if ($page == '') $page = $pageLink;
	$page = BOLTutf2url($page);
	if ($args['fmt'] != '') $fmt = $args['fmt'];
	else $fmt = $args[2];
	if ($args['dir'] != '') {
		$dir = $args['dir'];
		if ($dir == 'plugins') $dir = $pluginPath;
		if ($dir == 'system') $dir = $systemPath;
		if ($dir == 'pages') $dir = $pagesDir;
		}
	else {
		$dir = $pagesDir;
		$page = BOLTfolders($page);
		}
	if (file_exists("$dir/$page")) $time = filemtime("$dir/$page");
	elseif (file_exists("$systemPath/$page") && $dir == $pagesDir) $time = filemtime("$systemPath/$page");			
	if ($time == '') return;
	if ($fmt == '') return $time;
	return strftime($fmt, $time);
	}

function BOLTFlist($args, $zone='') {
## A POWERFUL FUNCTION THAT TAKES A CSV LIST AND RUNS THROUGH THE FMT/TEMPLATE ROUTINE. MANY PARAMETERS: DELIMITER, PAGE (AUTOMATICALLY CONVERTS TO CSV), FOR=1-5, JOIN (DEFAULTS TO LINE RETURN). TEMPLATE AND FMT WORK EXACTLY AS IN SEARCHES
	global $pageLink;
	if (isset($args['delimiter'])) $delimiter = $args['delimiter'];
	else $delimiter = ',';
	if (isset($args['page'])) {
		if (!isset($args['delimiter'])) $delimiter = "\n";
		$list = BOLTfilter($args['page'], 'csv');
		$list = trim(BOLTloadpage($list, '', '', true));
		}
	elseif (isset($args['for'])) {
		list($from, $to) = explode('-', $args['for'], 2);
		settype($to, 'integer');
		settype($from, 'integer');
		if ($from != $to) {
			if ($from < $to) {
				for ($i=$from; $i<$to+1; $i++) $list = $list . ",$i";
				}
			else {
				for ($i=$from; $i>$to-1; $i--) $list = $list . ",$i";
				}
			$list = trim($list, ',');
			}
		else $list = $to;
		}
	else $list = $args[1];
//	if ($list === NULL || $list === '') return;
	if (strpos($list, $delimiter) !== false) $outarray = explode($delimiter, $list);
	else $outarray[] = $list;
	if (isset($args['exclude'])) {
		$excludes = explode(',', $args['exclude']);
		foreach ($outarray as $i => $ii) {
			if (in_array($ii, $excludes)) unset($outarray[$i]);
			}
		}
	if (! isset($args['template']) && ! isset($args['fmt'])) $args['template'] = $args[2];
	return BOLTdisplay ($outarray, $args, $zone);
	}

function BOLTFlog($args, $zone='') {
## THIS FUNCTION TAKES YOUR PARAMETERS AND TAPS INTO THE SYSTEM'S LOGGING CAPABILITIES. PARAMETERS INCLUDE TARGET (DEFAULTS TO LOG.CURRENTPAGE), CONTENT(#1), DELIMITER & FLAGS. FLAGS INCLUDE DELETE/REMOVE, TRIM=5 (MAX), TOP (BOTTOM DEFAULT), SORT, UNIQUE, LINE=3 (REPLACE 3RD LINE)
	global $BOLTid, $pageLink;
	if ($args['target'] == '') $target = "log.$pageLink";
	else $target = BOLTpageshortcuts($args['target']);
	if (BOLTauth($target, $BOLTid, 'write') == false) return BOLTmsg('func_log_auth', "~$target", $args);
	$content = $args['content'];
	if ($content == '') $content = $args[1];
	$flags = $args['flags'];
	if ($content == '' && $flags == '') return;
	$content = preg_replace('/\\{\\+(\\w+)\\}/e', 'BOLTfieldreplace("$1", $args)', $content);	
	$content = str_replace('\n', "\n", $content);
	if (isset($args['delimiter'])) $delimiter = str_replace('\n', "\n", $args['delimiter']);
	else $delimiter = "\n";
	BOLTlog($content, $target, $delimiter, $flags);
	BOLTmsg('func_log', "~$target", $args);
	return BOLTloadpage($target);
	}

function BOLTFmail($args, $zone='') {
## BASIC MAIL FUNCTION FOR SENDING MAIL. MORE USEFUL AS A COMMAND PERHAPS. REQUIRED PARAMETERS: TO FROM SUBJECT AND BODY. TO/FROM CAN BE ID IF EMAIL ON PROFILE. IF NO BODY, LOOKS FOR #MAIL SECTION ON PAGE, OR CAN SET BODY=PAGE AND WILL USE PAGE. MAILMODE MUST BE ACTIVE IN SITE.CONFIG, AND USER HAVE AUTH ON SITE.AUTH.EMAIL. PROBABLY NEED A MODE=ACTIVE PARAMETER IN THE FUNCTION TO ALLOW YOU TO TEST INDIVIDUAL FUNCTIONS...
	global $pageLink, $actionLink, $BOLTid;
	$BOLTloginPages = BOLTconfig('BOLTloginPages', 'login');
	if (! isset($args['mode'])) $args['mode'] = BOLTconfig('BOLTmailmode', '');
//	if (! BOLTexists('site.auth.mail') || ! BOLTauth($pageLink, $BOLTid, 'mail')) return BOLTmsg('func_mail_auth', '', $args);
	if (isset($args['to'])) $to = $args['to'];
	else $to = BOLTconfig('BOLTsitemail');
	if (BOLTexists("$BOLTloginPages.$to")) $to = BOLTvars("$BOLTloginPages.$to:email", false);
	if (isset($args['from'])) $from = $args['from'];
	else $from = BOLTconfig('BOLTsitemail');
	if (BOLTexists("$BOLTloginPages.$from")) $from = BOLTvars("$BOLTloginPages.$from:email");
	$subject = $args['subject'];
	if (isset($args['body'])) {
		$body = $args['body'];
		if (BOLTexists($body)) {
			$templatePages = BOLTconfig('BOLTtemplatePages', 'template');
			if (substr($body, 0, strlen($templatePages) + 1) == "$templatePages.") $body = BOLTloadpage($body);
			else $body = BOLTloadpage($body, '', '', true);
			}
		}
	else $body = BOLTloadpage("$pageLink#mail");
	if ($to == '') $missing = ' TO';
	if ($from == '') $missing .= ' FROM';
	if ($subject == '') $missing .= ' SUBJECT';
	if ($body == '') $missing .= ' BODY';
	if ($missing != '') { BOLTmsg('func_mail_param', "~$missing", $args); return; }
	if (isset($args['reply'])) $reply = $args['reply'];
	else $reply = $from;
	if (isset($args['return'])) $reply = $args['return'];
	else $return = $from;
	$header = "From: $from\r\nReply-To: $reply\r\nReturn-Path: $return\r\n";
	if (isset($args['bcc'])) {
		if (! BOLTexists('site.auth.mail.bcc') || ! BOLTauth($pageLink, $BOLTid, 'mail.bcc')) return BOLTmsg('func_mail_bcc_auth', '', $args); 
		$bcc = explode("\n", BOLTloadpage($args['bcc']));
		foreach ($bcc as $i => $ii) {
			$ii = trim($ii);
			if (BOLTexists("$BOLTloginPages.$ii")) $ii = BOLTvars("$BOLTloginPages.$ii:email"); 
			if (preg_match('/^[\w]+\@[\w]+\.[\w]+$/', $ii) == 0) unset($bcc[$i]);
			else $bccArray[$i] = $ii;
			}
		$bcc = implode(',', $bccArray);
		$header .= "BCC: $bcc\r\n";
		$bcc = ' and ' . count($bccArray) . ' bcc recipients';
		}
	$body = preg_replace('/\\{\\+(\\w+)\\}/e', 'BOLTfieldreplace("$1", $args)', $body);
	$body = str_replace(Array('\n', '&#39;', '&#34;'), Array("\n", "'", '"'), $body);
	if ($args['content'] != '') {
		if ($args['content'] == 'simple') $rules = 'vars,if,links';
		elseif ($args['content'] == 'html') $rules = 'vars,if,links,fmt,block,style,end';
		elseif ($args['content'] == 'all') $rules = 'vars,func,if,form,links,fmt,block,style,end';
		else $rules = $args['content'];
		$body = BOLTdomarkup($body, '', '', $rules);
		$body = BOLTescape($body, false);
		if (strpos($body, '</') !== false && $args['content'] != 'simple') $html = 'true';
		$body = str_replace(Array('&amp;', '&lt;', '&gt;'), Array('&', '>', '<'), $body);
		}
	if ($html == 'true') {
		$header .= "MIME-Version: 1.0\r\nContent-Type: text/html; charset=ISO-8859-1\r\n";
//		$body = str_replace('&lt;', '<', $body);
		if (preg_match('/^\<html\>(.+)\<\/html\>$/m', $body) != 1) $body = "<html><body>$body</body></html>";
		}
	if ($args['mode'] != 'active') {
		$body = str_replace("\n", '<br />', $body);
		$out = "<b>Mail is in demo mode:</b><br />To: $to<br />" . str_replace("\r\n", '<br />', $header) . "<p /><br />Subject: $subject<p />$body";
		return BOLTescape($out);
//		return BOLTescape(preg_replace('/\@([-_a-z0-9.]+)/im', '@xxxxx.xxx', $out));
		}
	else {
		$body = BOLTescape($body, false);
		$sent = mail($to, $subject, $body, $header);
		if (! $sent) return 'Your mail server is not properly configured. Mail not sent.';
		return 'Mail has been sent';
//		$out = "Mail sent to $to$bcc.";
//		return BOLTescape(preg_replace('/\@([-_a-z0-9.]+)/im', '@xxxxx.xxx', $out));
		}
	}

function BOLTFmemberships($args='', $zone='') {
## THIS FUNCTION SCANS ALL GROUP PAGES AND REASSIGNS GROUP MEMBERSHIPS TO INDIVIDUAL. USEFUL FOR ACTIVATING NEW MEMBERSHIPS. OTHERWISE MUST WAIT TILL NEXT TIME THEY LOGIN. RETURNS AS A CSV LIST IF OUTPUT=TRUE. WOULD BE NICE TO TAP THIS INTO THE LIST FUNCTION
    global $BOLTid, $BOLTadmin, $BOLTfieldKey;
	$BOLTgroupPages = BOLTconfig('BOLTgroupPages', 'group');
    if (! is_array($args)) $args = BOLTargs($args); 
    $groups = BOLTlistpages("/^".$BOLTgroupPages."\./");
    session_name('BOLTsession');
    session_start();
    unset($_SESSION[$BOLTfieldKey]['GROUP']);
    if (! is_array($groups)) return;
    foreach ($groups as $group) {
        $groupname = substr($group, strlen($BOLTgroupPages) + 1);
        if (BOLTingroup("$groupname", $BOLTid, false)) $_SESSION[$BOLTfieldKey]['GROUP'][$groupname] = 1;
        }
	if (BOLTingroup('admin', $BOLTid, false)) $_SESSION[$BOLTfieldKey]['GROUP']['admin'] = 1; 
    $g = $_SESSION[$BOLTfieldKey]['GROUP'];
    session_write_close();
	BOLTmsg('func_memberships', '', $args);
    if ($args['output'] == 'true' && is_array($g)) {
        $g = array_keys($g);
        return implode(", ", $g);
        }
    }

function BOLTFnocache($args, $zone='') {
## PART OF THE CACHING SYSTEM--BASICALLY DISABLES CACHING OF THE CURRENT PAGE WHETHER IN THE PAGE OR IN AN INCLUDED ZONE
	global $BOLTnoCache, $pageLink;
	$page = BOLTgetlink('', $zone);
	if ($zone != main) $BOLTnoCache[$page] = true;
	if ($zone == 'main' || $args['main'] == 'true') $BOLTnoCache[$pageLink] = true;
	$BOLThtmlDir = BOLTconfig('BOLThtmlDir', 'html');
	if (file_exists("$BOLThtmlDir/$page.html")) unlink("$BOLThtmlDir/$page.html");
	$BOLTzonesDir = BOLTconfig('BOLTzonesDir', 'zones');
	if (file_exists("$BOLTzonesDir/$page.html")) unlink("$BOLTzonesDir/$page");
	}

function BOLTFoverwrite($args, $zone='') {
## A CUSTOM FUNCTION USED TO TELL WHICH PAGES IN YOUR SITE WILL BE OVERWRITTEN WHEN INSTALLING A BACKUP FILE. I WONDER IF SOME OF THESE RARELY USED FUNCTIONS COULD BE PUT SOMEWHERE ELSE TO TRIM DOWN THE CODE? A PLUGIN? A SCRIPT ONLY LOADED ON CERTAIN PAGES? JUST A THOUGHT.
	global $pagesDir, $systemPath, $pluginPath;
	$BOLTbackupsDir = BOLTconfig('BOLTbackupsDir', 'backups');
	$dir = $BOLTbackupsDir;
	if (isset($args['plugin'])) {
		$backup = BOLTfilter($args['plugin'], 'page');
		$dir = $pluginPath;
		}
	elseif (isset($args['backup'])) $backup = BOLTfilter($args['backup'], 'page');
	else $backup = BOLTfilter($args[1], 'page');
	if ($backup == '') return;
	$pages = BOLTloadpage($backup, $dir);
	if (strpos($pages, "\n~data~\n") !== false) $pages = substr($pages, 0, strpos($pages, "\n~data~\n"));
	if ($pages == '') return BOLTmsg('func_overwrite_nopages', '', $args);
	$dir = '';
	$p = explode ("\n", $pages);
	foreach ($p as $pp) {
		if (strpos($pp, "::") !== false) {
			$dir =  substr($pp, 0, strpos($pp, "::"));
			$pp = substr($pp, strpos($pp, "::") + 2);
			if (! file_exists($dir)) mkdir($dir);
			$index = substr($pp, 0, strpos($pp, ":"));
			if (file_exists("$dir/$index")) $out .= "$dir: $index\n";
			}
		else {
			$index = substr($pp, 0, strpos($pp, ":"));
			$findex = BOLTfolders($index);
			if (file_exists("$pagesDir/$findex")) $out .= "pages: $index\n";
			elseif (file_exists("$systemPath/$index")) $out .= "system: $index\n";
			}
		}
	if (isset($args['fmt'])) {
		$args[1] = str_replace("\n", ',', $out);
		return BOLTFlist($args);
		}
	if ($out == '' || $out == "pages: \n") return BOLTmsg('func_overwrite_ok', '', $args);
	return BOLTmsg('func_overwrite_warn', '', $args) . "\n\n" . $out;
	}

function BOLTFpreview($args, $zone='') {
## THIS SCRIPT IS USED TO ALLOW PREVIEW OF FORM SUBMISSIONS, SHOWING A POST VALUE IF EXISTS. MORE DOCUMENTATION IS NEEDED
	global $pageLink;
	$field = $args[1];
	if (isset($_POST[$field])) {
		$preview = $_POST[$field];
		if ($args['output'] == 'escape') return BOLTescape($preview);
		$preview = preg_replace('/(\[|\{|\<)\(preview(.*?)\)(\]|\}|\>)\n?/', '', $preview);
		$preview = str_replace(Array("\r\n", "\r"), Array("\n", "\n"), $preview); 
		if (substr($pageLink, 0, 5) == 'code.' || substr($pageLink, 0, 9) == 'template.') {
			$preview = BOLTescape($preview, false);
			$preview = htmlspecialchars($preview);
			$preview = BOLTcharEncode($preview, 'lines', false);
			return BOLTescape("<div class='preview'>" . ltrim($preview) . '</div>');
			}
		$preview = str_replace('[form', '[fo`rm', $preview);
		$preview = BOLTdomarkup("\n$preview", $pageLink, '', '', false);
		$preview = preg_replace('/([\\n]?)\[session( (?:"*.?"|\'*.?\'|\[\]|\]\]|=\]|[^\]])*)?\]/', '', $preview);
		$preview = preg_replace('/([\\n]?)\[fo~~[0-9]+~~m( (?:"*.?"|\'*.?\'|\[\]|\]\]|=\]|[^\]])*)?\]/', '$1', $preview);
		return BOLTescape("<div class='preview'>" . ltrim($preview) . '</div>');
		}
	}

function BOLTFrandom($args, $zone='') {
## RETURNS A RANDOM NUMBER BETWEEN #1 AND #2.
	if ((BOLTfilter($args[1], 'numbers')) === false || (BOLTfilter($args[2], 'numbers') === false)) return; 
	return rand($args[1], $args[2]);
	}

function BOLTFscript($args, $zone='') {
## A POWERFUL, LITTLE FUNCTION THAT ALLOWS YOU TO SET UP A MACRO USING THE FORMS PROCESSOR ENGINE. #1 IS SIMPLY THE NAME OF THE SCRIPT. LOADS SITE.SCRIPT.PAGE AND EXECUTES THE FORM. THE FORMAT ON THE PAGE SOULD BE SIMPLE LINES LIKE <:FIELD:>VALUE. EXECUTES AS A FORM WITHOUT PAGE SUBMISSION
	global $pageLink, $MarkUpTable, $BOLTabortKey;
	if ($BOLTabortKey == true) return;
	if (BOLTexists('code.script.' . $args[1])) $script = BOLTloadpage('code.script.' . $args[1]);
	else return;
	$script = BOLTdomarkup($script, $pageLink, 'script', 'vars,func,if');
	preg_match_all('/(&lt;):([_a-z0-9.]+):&gt; ?(.*?)(?=\n&lt;:|$)/s', $script, $commands);  // if enable full markup, change \n to <br />
	foreach ($commands[2] as $i => $ii) $BOLTexec[$ii] = $commands[3][$i];
	BOLTmsg('func_script', "~$args[1]", $args);
	BOLTexecute($BOLTexec, true);
	}

function BOLTFsearch($args, $zone='', $auth=true) {
## FUNCTION FOR SEARCHING INDEX. MANY POSSIBLE PARAMETERS. LIMIT PAGES BY PAGES, PATTERN, GROUP, INCLUDE, EXCLUDE, TYPE, FOLDER, DIR. SEARCH TEXT,DATA,LINK. ORGANIZE BY SORT,IF. OUTPUT IS TEMPLATE OR FMT
	global $pageLink, $pagesDir;
	if (BOLTconfig('BOLTsearchLimit') != '' && ! isset($args['count'])) $args['count'] = BOLTconfig('BOLTsearchLimit');
	$outarray = BOLTsearchPageList($args, $zone, $auth);
	if (count($outarray) < 1) return BOLTdisplay(Array(), $args, $zone);
	foreach($args as $f => $v) {
		if (! is_int($f)) continue;
		if (strpos($v, '(') === false || strpos($v, ')') === false) continue;
		$data[] = $v;
		unset($args[$f]);
		}
	if (! isset($args['text']) && isset($args[1])) $args['text'] = $args['1'];
	if (isset($args['text']) || isset($args['link']) || ! empty($data)) {
		$outarray = BOLTindexQuery($outarray, $args['index']);
		if (isset($args['text'])) $outarray = BOLTqueryText($outarray, $args['text'], $args);
		if (isset($args['link'])) $outarray = BOLTqueryLink($outarray, $args['link'], $args);
		if (is_array($data)) $outarray = BOLTqueryData($outarray, $data, $args);
		if (is_array($outarray)) $outarray = array_keys($outarray);
		else $outarray = Array();
		}
	return BOLTdisplay($outarray, $args, $zone);
	}	

function BOLTFsource($args, $zone='') {
## FLEXIBLE SCRIPT FOR RETURNING MARKUP FROM ANOTHER PAGE. MANY OPTIONS. PARAMETERS INCLUDE POST=FIELD (RETURN $_POST VALUE), SAME WITH GET. PAGE(#1), CAN TAKE ANCHOR AND PAGE SHORTCUTS. REQUIRES READ AUTH. CAN RETRIEVE LINES=5 OR LINES=5..10. USE FMT=LINES TO CREATE LINE BREAKS (FOR DISPLAYING MARKUP), LEAVE OUT IF FILLING A TEXTBOX. CAN SET ESCAPE=FALSE TO NOT ESCAPE, AND REPLACETABLE=TRUE TO TRIGGER ROO TABLE (REPLACE ON OPEN) 
	global $pageLink, $BOLTid, $BOLTreplaceTable;
	if (!is_array($args)) $args = BOLTargs($args);
	if (isset($args['post']) && isset($_POST[$args['post']])) return BOLTescape(htmlspecialchars($_POST[$args['post']], ENT_NOQUOTES));
	if (isset($args['get']) && isset($_GET[$args['get']])) return BOLTescape(htmlspecialchars($_GET[$args['get']], ENT_NOQUOTES));
	if (isset($args['page'])) $page = $args['page'];
	else $page = $args[1];
	if (strpos($page, ':') !== false) {
		$data = substr($page, strpos($page, ':'));
		$page = substr($page, 0, strpos($page, ':'));
		}
	if (strpos($page, '#') !== false) {
		$anchor = substr($page, strpos($page, '#'));
		$page = substr($page, 0, strpos($page, '#'));
		}
	$page = BOLTpageshortcuts($page);
	if (BOLTfilter($page, 'page') == '') return;
	if ($page == '') $page = $pageLink;
	if (BOLTauth($page, $BOLTid, 'view') === false) BOLTmsg('func_source_auth', "~$page", $args);
	if ($data != '') $out = BOLTvars("$page$data");
	else {
		$out = htmlspecialchars(BOLTloadpage("$page$anchor"), ENT_NOQUOTES);
		if (isset($args['lines'])) $out = BOLTgetlines($out, $args['lines']);
		}
	if ($args['replacetable'] == 'true' && is_array($BOLTreplaceTable['OPEN'])) $out = strtr($out, $BOLTreplaceTable['OPEN']);
	$out = BOLTcharEncode($out, $args['fmt']);
	if ($args['escape'] === 'false') $out = BOLTescape($out, false);
	BOLTmsg('func_source', "~$page", $args);
	return $out;
	}

function BOLTFtime($args, $zone='') {
## VERSATILE TIME FUNCTION. WHEN(#1) IN TIMESTAMP OR TEXT EXPRESSION. FMT(#2 IS STRFTIME RECOGNIZABLE VALUE, WITH ADDITION OF %E (DATE, WITH NO SPACE). CAN SET A DEFAULT TIMEFMT IN SITE.CONFIG. OR CAN SET FMT=DUE WITH DUE=TIME IN SECONDS (DEFAULTS 86400, DAYS). OFFSET (SHOULD BE DECIMAL) NUMBER OF PLACES
	global $BOLTtime;
	if ($args == Array()) $t = $BOLTtime;
	else {
		if (isset($args['when'])) $t = BOLTfilter($args['when'], 'parameter');
		else $t = $args[1];
		if (! is_numeric($t) || strlen($t) != 10) $t = strtotime($t);
		}
	if (isset($args['fmt'])) $f = BOLTfilter($args['fmt'], 'parameter');
	else $f = BOLTfilter($args[2], 'parameter');
	if ($f == '') {
		$f = $args[1];
		$t = $BOLTtime;
		}
	if ($f == 'due') $args['due'] = '86400';
 	if (isset($args['due'])) {
		if (is_numeric($args['offset'])) $o = $args['offset'];
		return round($t/$args['due']) - round($BOLTtime/$args['due']) + $o;
		}
	if ($f == '') $f = BOLTconfig('BOLTtimeFmt');
	if ($f == '') return $t;
	if (strpos($f, '%E') !== false) $f = str_replace('%E', ltrim(strftime('%d', $t),0), $f);
	return strftime($f, $t);
	}

function BOLTFtoc ($args, $zone='') {
## A SPECIALIZED FUNCTION FOR TEMPLATES TO INDENT BASED ON HOW MANY PAGE PARTS IN PAGE NAME. PARAMETERS #1 IS PAGE NAME. LEADER DEFAULTS TO 6 SPACES, OFFSET CAN SUBTRACT 1 OR MORE INDENTIONS
	if (isset($args[1])) $myArray = explode('.', $args[1]);
	else {
		global $pageArray;
		$myArray = $pageArray;
		}
	if (isset($args['leader'])) $leader = $args['leader'];
	else $leader = '      ';
//	foreach ($myArray as $x) $out = $out . $leader;
	$out = str_repeat($leader, count($myArray));
	if (is_numeric($args['offset'])) {
		$offset = $args['offset'] * strlen($leader);
		$out = substr($out, $offset);
		}
	return $out;
	}

function BOLTFtouch($args, $zone='') {
## THIS FUNCTION RESETS LASTMODIFIED TIME. USEFUL IN FORCING CACHES TO REFRESH. PARAMETERS INCLUDE PAGE(#1) AND TIME (TIMESTAMP OR TEXT)
	global $pageLink, $pagesDir;
	$page = $args['page'];
	if ($page == '') $page = $args[1];
	if ($page == '') $page = $pageLink;
	$time = strtotime($args['time']);
	if ($time == '') $time = time();
	if (BOLTexists($page)) touch("$pagesDir/$page", $time);
	}

function BOLTFtranslate($args, $zone='') {
## FUNCTION FOR TAPPING INTO THE TRANSLATION ENGINE FOR PHRASE IN #1. CAN SPECIFY LANGUAGE (IF NOT DEFAULT) AND/OR REVERSE=TRUE TO TURN BACK TO ENGLISH
	if (isset($args['language'])) $language = $args['language'];
	if ($args['reverse'] == 'true') $reverse = 1;
	return BOLTtranslate($args[1], $language, $reverse);
	}

function BOLTFzones($args, $zone='') {
## SPECIALIZED FUNCTIONS WHICH ANALYZES SKIN FOR CURRENT PAGE, IDENTIFIES ALL ZONES AND GENERATES A TABLE WITH LIST OF ALL THE PAGES USED TO CREATE OUTPUT (VIEW, EDIT, SOURCE)
	global $pageLink;
	$BOLTcodePages = BOLTconfig('BOLTcodePages', 'code');	
	$skin = BOLTgetlink($BOLTcodePages, 'skin');
	$contents = BOLTloadpage($skin);
	preg_match_all('/\<\<([a-z0-9]+)\>\>/', $contents, $z1);
	preg_match_all('/\[\[([a-z0-9]+)\]\]/', $contents, $z2);
	if ($args[1] == 'code') return 'skin,' . implode(',', $z1[1]);
	if ($args[1] == 'content') return implode(',', $z2[1]);
	return 'skin,' . implode(',', $z1[1]) . ',' . implode(',', $z2[1]);
	}
Return current item: BoltWire