Location: PHPKode > projects > BoltWire > barn/scripts/engine.php
<?php

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


## INITIALIZATION ROUTINE
## BEGINS BY SETTING VARIOUS ENVIRONMENT VALUES. THEN LOADS CONFIG VALUES FROM SITE.CONFIG PAGE. DETERMINES WHICH PAGE TO SHOW AND SET CERTAIN PAGE VARIABLES. LOOKS FOR CACHED HTML PAGE IF TURNED ON. SETS CERTAIN INTERNAL VARIABLES, GETS MEMBER/GROUP, MESSAGING & QUERY INFO, AND SETS MOST SYSTEM VARIABLES. NEXT, LOADS SYSTEM SCRIPTS, CONFIG FILES & ENABLED PLUGINS. BLACKLISTING/WHITELISTING IS HANDLED. FORMS PROCESSOR IS RUN IF NEEDED. PAGE IS PREPARED FOR DISPLAY. AND LASTLY BACKGROUND FUNCTIONS ARE RUN.

## ENVIRONMENT VARIABLES. ENABLE ERRORREPORTING IN INDEX.PHP BEFORE CALLING ENGINE
BOLTstopWatch('Begin Initialization');
$BOLTWIRE = "v3.4.14";
define('BOLTWIRE',1);
BOLTdefault($errorReporting, false);
if ($errorReporting == true || $_GET['errors'] == 'true') error_reporting(E_ALL ^ E_NOTICE);
else error_reporting(0);

## CLEAN UP SOME PROBLEMS WITH PHP WEAKNESSES. WILL BE DEPRECATED WITH PHP6 I THINK...
if (ini_get('register_globals')) {
	foreach($_REQUEST as $k => $v) {
		if (preg_match('/^(GLOBALS|_SERVER|_GET|_POST|_COOKIE|_FILES|_ENV|_REQUEST|_SESSION)$/i', $k)) exit();
		unset(${$k});
		}
	}
if (get_magic_quotes_gpc() == 1) {
	foreach($_GET as $field => $value) $_GET[$field] = stripslashes($value);
	foreach($_POST as $field => $value) {
		if (is_array($value)) $_POST[$field] = array_map(stripslashes, $value);
		else $_POST[$field] = stripslashes($value);
		}
	}

## SETUP PATHS, URLS AND DIRS. CHANGE IN INDEX.PHP ONLY IF A NONSTANDARD INSTALLATION STRUCTURE
BOLTdefault($boltwire, '../boltwire');
BOLTdefault($barnPath, "$boltwire/barn");
BOLTdefault($scriptPath, "$barnPath/scripts");
BOLTdefault($systemPath, "$barnPath/system");
BOLTdefault($farmPath, "$boltwire/farm");
BOLTdefault($imgPath, "$farmPath/img");
BOLTdefault($pubPath, "$farmPath/pub");
BOLTdefault($pluginPath, "$farmPath/plugins");
BOLTdefault($skinPath, "$farmPath/skins");
BOLTdefault($fieldURL, dirname("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI] ") . '/');
BOLTdefault($farmURL, "http://$_SERVER[HTTP_HOST]/boltwire/farm");
BOLTdefault($imgURL, "$farmURL/img");
BOLTdefault($pubURL, "$farmURL/pub");
BOLTdefault($fieldName, substr($fieldURL, strrpos(substr($fieldURL, 0, -1), "/") + 1, -1));
BOLTdefault($index, 'index.php');
BOLTdefault($scriptURL, "$fieldURL$index?p=");
BOLTdefault($pagesDir, 'pages');
BOLTdefault($configDir, 'config');
if (! file_exists($pagesDir)) {  // first time run...
	BOLTfixdir($pagesDir);
	BOLTfixdir($configDir);
	}

## THIS SECTION LOADS CONFIG VALUES FROM SITE.CONFIG PAGE, LOCAL IF FOUND OR SYSTEM.
//if (file_exists("$pagesDir/site.config")) $config = file_get_contents("$pagesDir/site.config");
//else $config = file_get_contents("$systemPath/site.config");
//if (strpos($config, "~data~") !== false) $config = substr($config, 0, strpos($config, "~data~"));
$config = BOLTloadpage('site.config');
preg_match_all('/^(enable([-\w]+)\:?|([-\w]+)\:)(([-\w]*)\:)?(.*)?$/m', $config, $m);
foreach ($m[6] as $i => $v) {
	if ($m[2][$i] != '') $BOLTplugins[strtolower($m[2][$i])] = trim($v);
	elseif ($m[4][$i] != '') $BOLTconfig[strtolower($m[3][$i])][strtolower($m[5][$i])] = trim($v);
	else $BOLTconfig[strtolower($m[3][$i])] = trim($v);
	}

## DETERMINE WHICH PAGE TO SHOW AND SET CERTAIN PAGE VARIABLES. 
if ($_GET['p'] == '') $pageLink = BOLTconfig('BOLTdefaultPage', 'main');
else $pageLink = $_GET['p'];
$BOLTutfEscapeChars = Array('%','<','>','/','\\','*',':',',','~','@','+','^','!','#','&','$',';','=','?',"\n");
foreach ($BOLTutfEscapeChars as $char) {
	$code = urlencode($char);
	$BOLTutfEscape[$code] = $char;
	$BOLTutfEscape[strtolower($code)] = $char;
	}
$pageLink = strtolower(BOLTutf2url($pageLink));
if (strpos($pageLink, "=") !== false) $pageLink = str_replace("=", ".", $pageLink);
if (isset($cleanURL)) $pageLink = str_replace(Array('/', '%2f'), '.', $pageLink);
$pageLink = strtolower(trim($pageLink, '.'));
if (preg_match('/^[-_a-zA-Z0-9\.%]+$/', $pageLink) == 0) {
	print_r("Invalid page name.");
	exit();
	}
$pageArray = explode(".", $pageLink);

## SETUP MEMBER/GROUP AUTHENTICATION, MESSAGING, AND QUERY VARS. RETURN CACHED HTML IF ENABLED AND NOT LOGGED IN
$BOLTfieldKey = BOLTconfig('BOLTfieldKey', $fieldName);
session_start();
$BOLTsession = $_SESSION[$BOLTfieldKey];
unset($_SESSION[$BOLTfieldKey]['MSG']);
unset($_SESSION[$BOLTfieldKey]['QUERY']);
unset($_SESSION[$BOLTfieldKey]['FORM'][$pageLink]);
unset($_SESSION[$BOLTfieldKey]['POST']);
unset($_SESSION[$BOLTfieldKey]['KEY'][$pageLink]);
unset($_SESSION[$BOLTfieldKey]['CONFLICT']);
session_write_close();
$BOLTabortGET = $BOLTsession['KEY'][$pageLink]['GET'];

if (isset($BOLTsession['ID'])) {
	$BOLTmember = $BOLTsession['ID']['member'];
	$BOLTid = $BOLTsession['ID']['id'];
	if (is_array($BOLTsession['GROUP'])) {
		$g = $BOLTsession['GROUP'];
		$g = array_keys($g);
		}
	$BOLTmemberships = 'guest,member';
	if (is_array($g)) $BOLTmemberships = $BOLTmemberships . ',' . implode(",", $g);
	}
else {
## IF HTML CACHING ENABLED AND NOT LOGGED IN LOOKS FOR HTML PAGE AND RETURNS
	if (BOLTconfig('BOLTcacheHTML', 'false') == 'true') {
		if ($_GET['action'] == '' && $pageArray[0] != 'action' && $_POST == Array()) {
			$BOLThtmlDir = BOLTconfig('BOLThtmlDir', 'html');
			if (file_exists("$BOLThtmlDir/$pageLink.html")) {
				if (! file_exists("$pagesDir/$pageLink")) unlink("$BOLThtmlDir/$pageLink.html");
				else {
					if (BOLTconfig('BOLTcacheLimit') > 0 && BOLTconfig('BOLTcacheLimit') < time() - filemtime("$BOLThtmlDir/$pageLink.html")) {
						unlink("$BOLThtmlDir/$pageLink.html");
						}
					elseif (filemtime("$BOLThtmlDir/$pageLink.html") > filemtime("$pagesDir/$pageLink")) {
						global $BOLTstopWatchMsg;
						BOLTstopWatch('Cached Page Returned.');
						print_r($BOLTstopWatchMsg . file_get_contents("$BOLThtmlDir/$pageLink.html"));
						exit();
						}
					}
				}
			}
		if ($_GET['action'] == 'view' && file_exists("$BOLThtmlDir/$pageLink.html")) unlink("$BOLThtmlDir/$pageLink.html");
		}
	$BOLTmember = BOLTconfig('BOLTguestname', 'Guest');
	$BOLTmemberships = 'guest';
	}
if (isset($BOLTsession['MSG'])) $msg = $BOLTsession['MSG'];
if (isset($BOLTsession['QUERY'])) $query = $BOLTsession['QUERY'];
if (isset($BOLTsession['LASTQUERY'][$pageLink])) $lastquery = $BOLTsession['LASTQUERY'][$pageLink];

## SETUP CERTAIN INTERNAL VARIABLES
if (is_array($BOLTconfig['skin'])) {
	foreach($BOLTconfig['skin'] as $skin => $check) {
		if (BOLTpageCheck($check)) $BOLTskin = $skin;
		}
	}
else $BOLTskin = BOLTconfig('BOLTskin');

$BOLTtime = time() + BOLTconfig('BOLTlocalTime', 0) * 3600;
$BOLTformJs['clear'] = "onFocus=this.value=''";
$BOLTformJs['submit'] = "onClick='this.form.submit()'";
$BOLTfilter['letters'] = 'a-z';
$BOLTfilter['numbers'] = '0-9';
$BOLTfilter['page'] = '-_a-zA-Z0-9.#?=%*';
$BOLTfilter['csv'] = '-_a-zA-Z0-9+.,*:|!#% ';
$BOLTfilter['parameter'] = '-_a-zA-Z0-9.,\'"%:!/ ';
$BOLTfilter['math'] = '-*+/% ()0-9.';
$BOLTmyFilter['title'] = Array('&#39;'=>'','&#34;'=>'', ' '=>'-', '/[\\.,\'":;?!]/'=>'');
BOLTreplace('~~~', "[[~.$BOLTid|$BOLTmember]], " . strftime('%x'), 'SAVE');
BOLTreplace('~~', "[[~.$BOLTid|$BOLTmember]]", 'SAVE');
$BOLTattrs['form'] = 'name,class,id,style,action';
$BOLTattrs['text'] = 'name,value,size,maxlength,class,id,style,disabled';
$BOLTattrs['checkbox'] = 'name,size,checked,value,class,id,style,disabled';
$BOLTattrs['radio'] = 'name,value,size,maxlength,checked,class,id,style,disabled';
$BOLTattrs['password'] = 'name,value,size,maxlength,class,id,style,disabled';
$BOLTattrs['hidden'] = 'name,value,size,maxlength,class,id';
$BOLTattrs['image'] = 'name,src,alt,align,class,id,disabled';
$BOLTattrs['select'] = 'name,size,multiple,class,id,style,disabled';
$BOLTattrs['option'] = 'value,selected,class,id,style,disabled';
$BOLTattrs['box'] = 'name,cols,rows,class,id,style,disabled';
$BOLTattrs['file'] = 'name,size,maxlength,class,id,style,disabled';
$BOLTattrs['button'] = 'name,value,class,id,style,disabled';
$BOLTattrs['submit'] = 'name,value,class,id,style,disabled';
$BOLTattrs['reset'] = 'value,class,id,style,disabled';
$BOLTattrs['t'] = 'align,background,bgcolor,border,bordercolor,cellpadding,cellspacing,width,style,class,id';
$BOLTattrs['r'] = 'align,background,bgcolor,valign,cellpadding,cellspacing,border,style,class,id';
$BOLTattrs['c'] = 'align,background,bgcolor,valign,border,cellpadding,cellspacing,colspan,rowspan,nowrap,valign,width,style,class,id';
$BOLTattrs['h'] = $BOLTattrs['c'];
$BOLTattrs['a'] = 'id,class,href,name,style,rev,rel,target,title,accesskey,tabindex,class,id,xmllang';
$BOLTattrs['span'] = 'id,class,style,align,border,bottom,class,clear,color,float,height,left,letter-spacing,margin,padding,position,right,top,width,z-index';
$BOLTattrs['p'] = 'id,class,style,align,border,bottom,class,clear,color,float,height,left,letter-spacing,margin,padding,position,right,top,width,z-index';
$BOLTattrs['div'] = 'id,class,style,align,border,bottom,class,clear,color,float,height,left,letter-spacing,margin,padding,position,right,top,width,z-index';
$BOLTattrs['ul'] = 'id,class,style';
$BOLTattrs['ol'] = 'id,class,style';
$BOLTattrs['li'] = 'id,class,style';
$BOLTattrs['img'] = 'align,border,style,class,height,width,hspace,vspace,title,alt';
$BOLTattrs['html'] = 'i,b,u,s,h1,h2,h3,h4,h5,h6,ul,ol,li,dl,dt,dd,sub,sup,big,small,strike,strong,em,comment,br,nobr,wbr,fieldset,legend';
$BOLTattrs['session'] = 'authkey,backup,copy,create,delete,edit,enable,if,info,join,log,login,mail,register,rename,reset,restore,savedata,unstamp,validate,upload';
$BOLTvar['$version'] = $BOLTWIRE;
$BOLTvar['$now'] = $BOLTtime;
$BOLTvar['$captcha'] = rand(1000,9999);
$BOLTvar['$return'] = substr($_SERVER[HTTP_REFERER], strpos($_SERVER[HTTP_REFERER], "?p=") + 3);
$BOLTvar['$ip'] = $_SERVER[REMOTE_ADDR];
$BOLTvar['$ip2'] = str_replace('.', '-', $_SERVER[REMOTE_ADDR]);
$BOLTvar['$domain'] = $_SERVER[SERVER_NAME];
$BOLTvar['$field'] = $fieldName;
$BOLTvar['$fieldurl'] = $fieldURL;
$BOLTvar['$skin'] = $BOLTskin;
$BOLTvar['$script'] = $scriptURL;
$BOLTvar['$action'] = $_GET['action'];
$BOLTvar['$id'] = $BOLTid;
$BOLTvar['$sessid'] = strtolower(substr(session_id(), 0, 16));
$BOLTvar['$member'] = $BOLTmember;
$BOLTvar['$memberships'] = $BOLTmemberships;
$BOLTvar['$language'] = BOLTconfig('BOLTlanguage');
$BOLTvar['$sitemail'] = BOLTconfig('BOLTsitemail');
$BOLTvar['$superadmin'] = $BOLTadmin;
if (BOLTvars("$pageLink:author") == $BOLTmember) $BOLTmemberships = ltrim("$BOLTmemberships,author", ', ');
if ($BOLTconfig['language'] != '') {
	$languageAction = BOLTtranslate('action');
	if (isset($_GET[$languageAction])) $_GET['action'] = $_GET[$languageAction];
	$_GET['action'] = BOLTtranslate($_GET['action'], $BOLTconfig['language'], 1);
	}
$BOLTautolines = BOLTconfig('BOLTautoLines', 'true');
BOLTprocess('startup');

## LOAD REMAINING SCRIPTS, CHECKING CONFIG FOLDER FOR REPLACEMENTS, CONFIGS, & ENABLED PLUGINS
$BOLTscripts = Array('markups', 'functions', 'conditions');
foreach($BOLTscripts as $script) {
	$f = BOLTgetlink('', "$script.php", '', $configDir);
	if (file_exists($f)) include_once($f);
	elseif (file_exists("$scriptPath/$script.php")) include_once("$scriptPath/$script.php");
	}
if (file_exists("$configDir/config.php")) include_once("$configDir/config.php");
$config = BOLTgetlink('config', 'php', '', $configDir);
if (file_exists($config)) include_once($config);
if (is_array($BOLTplugins)) {
	foreach($BOLTplugins as $plugin => $check) {
		if (file_exists("$pluginPath/$plugin.php")) {
			if(BOLTpageCheck($check)) {
				include_once("$pluginPath/$plugin.php");
				$BOLTvar['$plugins'] .= ",$plugin";
				}
			}
		}
	$BOLTvar['$plugins'] = trim($BOLTvar['$plugins'], ",");
	}

## BLACKLISTING/WHITELISTING HANDLED HERE
$BOLTblackList = BOLTconfig('BOLTblackList');
$BOLTwhiteList = BOLTconfig('BOLTwhiteList');
if ($BOLTblackList != '' || $BOLTwhiteList != '') {
	BOLTdefault($IPblockedHTML, 'Access Denied');
	if ($BOLTwhiteList != '' && strpos(BOLTloadpage($BOLTwhiteList), $BOLTvar['$ip']) === false) {print_r($IPblockedHTML);die();}
	elseif ($BOLTblackList != '' && strpos(BOLTloadpage($BOLTblackList), $BOLTvar['$ip']) !== false) {print_r($IPblockedHTML);die();}
	}
//	if ($errorReporting == true) BOLTmsg('register_globals', 'Your current php settings has register_globals turned ON. Please disable for improved security.');

## RUN FORMS PROCESSOR IF NEEDED, PREPARE PAGE FOR DISPLAY, RUN BACKGROUND FUNCTIONS
BOLTstopWatch('Initialization Complete');
if (isset($_POST['boltkey'])) BOLTexecute(BOLTsecure());

//print_r($BOLTstopWatchMsg . BOLTmakepage()); die();
$out = $BOLTstopWatchMsg . BOLTmakepage();
if (! $errorReporting) {
	ob_end_clean();
	header("Connection: close");
	ob_start();
	echo ($out);
	$size = ob_get_length();
	header("Content-Length: $size");
	ob_end_flush();
	flush(); 
	}
else echo $out;
ignore_user_abort();
set_time_limit(120);
$BOLTindexing = BOLTconfig('BOLTindexing', 'active');
if ($BOLTindexing == 'active' && is_array($BOLTindexPages)) {
	$BOLTindexPages = array_unique($BOLTindexPages);
	$indexArgs['pages'] = implode(',', $BOLTindexPages);
	BOLTindex($indexArgs);
	}
BOLTprocess('background');
exit;

## END INITIALIZATION

## FOLLOWING ARE ALL THE SYSTEM FUNCTIONS USED IN BOLTWIRE IN ALPHATBETICAL ORDER

function BOLTabort($id, $value='', $func='COMMAND') {
## ADDS A MESSAGE TO THE MSG ARRAY AND SHUTS DOWN PROCESSING IMMEDIATELY. GENERALLY USED BY (FORM) COMMANDS THAT FAIL SOME KIND OF TEST
	if ($func != 'COMMAND') return $value;
	BOLTmsg($id, $value);
	global $BOLTabortKey, $BOLTabortGET;
	$BOLTabortKey = true;
	$_GET = $BOLTabortGET;
	header("Content-Type: text/html; charset=utf-8");
	print_r(BOLTmakepage());
	BOLTprocess('post');
	exit;
	}

function BOLTargs($x, $type='', $optpat='(?>(\\w+)=)') {
## POWERFUL FUNCTION FOR PARSING A PARAMETER STRING INTO AN ARRAY, USED MANY PLACES.
	$x = BOLTstripslashes($x);
	$x = preg_replace('/([a-z])(\')([a-z])/', '$1&#39;$3', $x);
	$count = 0;
	preg_match_all("/($optpat|[-+])?(\"[^\"]*\"|'[^']*'|\\S+)/", $x, $terms, PREG_SET_ORDER);
	foreach($terms as $t => $tt) {
		if ($terms[$t][2] == '') {
			$count = $count + 1;
			$args[$count] = BOLTtrimQuotes($terms[$t][3]);
			}
		else $args[$terms[$t][2]] = BOLTtrimQuotes($terms[$t][3]);
		}
	if (function_exists('myBOLTargs')) $args = myBOLTargs($args, $type);
	if (is_array($args)) return $args;
	return Array();
	}

function BOLTattrs($type) {
## A SIMPLE SCRIPT TO SET DEFAULT ALLOWED ATTRS FOR MANY FUNCTIONS IF NOT SET IN CONFIG FILE FIRST. TO MODIFY THE DEFAULTS, ADD A LINE LIKE: $BOLTattrs['type'] = 'my,csv,list'; AND YOURS WILL BE USED
	global $BOLTattrs;
	return explode(",", $BOLTattrs[$type]);
	}

function BOLTauth($check, $find, $type, $admin=true) {
## THIS FUNCTION IS USED TO CHECK VARIOUS PERMISSIONS: VIEW, WRITE, OR ANY OTHER TYPE. NORMALLY CHECK IS FOR PAGE AND FIND IS MEMBER BUT CAN BE OTHER VALUES. PLUGIN WRITERS CAN ADD ANY NEW TYPE DESIRED. RETURNS TRUE IF SUPERADMIN, SITE.AUTH PAGE DOESN'T EXIST OR FIND IS FOUND IN THE CLOSEST HIERARCHICAL CHECKLINE CSVLIST
	global $BOLTmemberships, $BOLTadmin, $BOLTid, $authlist;
	if ($admin) {
		if (strpos(" ,$BOLTadmin,", ",$BOLTid,") && $BOLTadmin != '') return true;
		}
	if ($type == '') BOLTabort('invalid_auth', "There was an invalid authorization attempt.");
	if ($check == '') return false;
	$check = BOLTurl2utf($check);
	if (! BOLTexists("site.auth.$type")) return true;
	$contents = BOLTloadpage("site.auth.$type");
	if ($contents == '') return false;
	$contents = str_replace('{id}', $BOLTid, $contents);
	$authlist = explode("\n", $contents);
	foreach ($authlist as $line) {
		$pos = strpos($line, ": ");
		if ($pos === false) continue;
		$f = substr($line, 0, $pos);
		$v = trim(substr($line, $pos + 2));
		$auth[$f] = $v;
		}
// Determine which auth line to use
	if ($type == 'data') {
		$page = substr($check, 0, strpos($check, ":"));
		if (strtolower(BOLTutf2url($page)) == BOLTconfig('BOLTloginPages', 'login') . '.' . $BOLTid) $find .= ',@owner';
		$check = substr($check, strlen($page) + 1);
		if (isset($auth[$check])) $checkline = $check;
		else $checkline = '*';
		}
	else {
		$checkline = '*';
		if (isset($auth[$check]) != '') $checkline = $check;
		else {
			$checkArray = explode('.', $check);	// find closest hg page set
			while (count($checkArray) > 0) {
				$test = implode('.', $checkArray) . "*";
				if ($auth[$test] != '') {
					$checkline = $test;
					break;
					}
				array_pop($checkArray);
				}
			}
		if (strtolower(BOLTutf2url($check)) == BOLTconfig('BOLTloginPages', 'login') . '.' . $BOLTid) $find .= ',@owner';
		}
	$auth[$checkline] = str_replace(' ', '', $auth[$checkline]);
	if ($type == 'commands' || $type == 'functions') {
		if (strpos(",$auth[$checkline],", ",$find,") !== false) return false;
		return true;
		}
	if ($auth[$checkline] == '') return false;
// Build auth membership list
	$find .= ',@' . str_replace(',', ',@', $BOLTmemberships);
// Determine if id has permission on that line
	$f = explode(',', trim($find,','));
	foreach ($f as $ff) {
		if (strpos(",$auth[$checkline],", ",$ff,") !== false) return true;
		}
	return false;
	}

function BOLTcharEncode($text, $fmt='', $escape=true) {
## SIMPLE FUNCTION TO ESCAPE A FEW STRINGS USED IN SOURCE CODE TYPE FUNCTIONS
	$text = str_replace(Array('[messages', '[results', '[fo>rm'), Array('%5Bmessages', '%5Bresults', '[form'), $text);
	if ($fmt == 'lines') $text = str_replace(Array("\n", '  ', "\t"), Array("<br />\n", '&nbsp;&nbsp;', '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'), $text);
	if ($escape) return BOLTescape($text);
	return $text;
	}

function BOLTcomm2func($value, $field) {
## A USEFUL UTILITY FUNCTION USED THAT ENABLES FORM COMMANDS TO TAP INTO CORRESPONDING FUNCTIONS
	global $BOLTarray, $target;
	if (strpos($field, '_') !== false) $field = substr($field, 0, strpos($field, '_'));
	if (isset($target) && ! isset($args['target'])) $args['target'] = $target;
	$args = BOLTargs($value, "x_$field");
	if (is_array($BOLTarray)) $args = $args + $BOLTarray;
	return BOLTfunc($field, $args, 'COMMAND');
	}

function BOLTconfig($field, $default='') {
## SYSTEM FUNCTION USED TO RETRIEVE CONFIG VALUES FOUND IN SITE CONFIG
	global $BOLTconfig;
	if (substr($field, 0, 4) == 'BOLT') {
		$field = strtolower(substr($field, 4));
		if (strpos($field, ':')) {
			$a = substr($field, 0, strpos($field, ':'));
			$k = substr($field, strpos($field, ':') + 1);
			if (isset($BOLTconfig[$a][$k])) return $BOLTconfig[$a][$k];
			return $default;
			}
		if (isset($BOLTconfig[$field])) return $BOLTconfig[$field];
		return $default;
		}
	}

function BOLTcrypt($value) {
## SIMPLE SYSTEM FOR ENCRYPTING VALUES (PASSWORDS USUALLY) WITH HOOK FOR CUSTOM ENCRYPTION METHOD
	if(function_exists('myBOLTcrypt')) return myBOLTcrypt($value);
	$BOLTcrypt = BOLTconfig('BOLTcrypt');
//	global $BOLTcryptKey;
	if ($BOLTcrypt == false) return $value;
	return crypt($value, $BOLTcrypt);
	}

function BOLTcsv($value, $current='') {
## USED FOR LIST AND GROUP MANAGEMENT. TO ADD OR REMOVE ITEMS USE +ITEM,-ITEM. IF NO $CURRENT IS SUPPLIED, IT TRIMS EACH ITEM AND RETURNS CLEANED $VALUE.
	if ($current == '') $c = -3;
	else $c = -2;
	$list = ",,$current,,";
	$i = explode(",", $value);
	foreach ($i as $ii) {
		$ii = trim($ii);
		$flag = substr($ii, 0, 1);
		$item = trim(substr($ii, 1));
		if ($current == '') {
			if ($flag == '-' || $flag == '+') $list = substr($list, 0, -2) . $item . ",,,";
			else $list = substr($list, 0, -2) . $ii . ",,,";
			}
		else {
			if ($flag == "-" && strpos($list, ",$item,")) $list = str_replace(",$item,", ",", $list);			
			elseif ($flag == "+" && ! strpos($list, ",$item,")) $list = substr($list, 0, -1) . $item . ",,";
			}
		}
	return substr($list, 2, $c);
	}

function BOLTdefault(&$field, $default) {
## SYSTEM FUNCTION USED TO SET DEFAULT VALUES THAT CAN BE OVERRIDDEN IN CONFIG FILE
	if (ini_get('register_globals')) {
		if (isset($_REQUEST[$field])) die();
		}
	if (!isset($field)) $field = $default;
	}

function BOLTdefaultArray(&$array,$default) {
## SYSTEM FUNCTION USED TO DEFINE DEFAULT ARRAYS THAT CAN BE OVERRIDDEN IN CONFIG FILE
	if (ini_get('register_globals')) {
		if (isset($_REQUEST[$array])) die();
		}
	foreach($default as $f=>$v) if (!isset($array[$f])) $array[$f]=$v;
	}

function BOLTdiff($old, $new) {
## SYSTEM FUNCTION USED TO GENERATE THE ACTUAL DIFF RESULTS USED BY BOLTFdiff.
	$t1 = explode("\n", $old);
	$x = array_pop($t1); 
	if ($x > '') $t1[] = "$x\n";
	$t2 = explode("\n", $new);
	$x = array_pop($t2); 
	if ($x > '') $t2[] = "$x\n";
	$t1_start = 0; $t1_end = count($t1);
	$t2_start = 0; $t2_end = count($t2);
	while ($t1_start < $t1_end && $t2_start < $t2_end && $t1[$t1_end-1] == $t2[$t2_end-1]) { $t1_end--; $t2_end--; }
	while ($t1_start < $t1_end && $t2_start < $t2_end && $t1[$t1_start] == $t2[$t2_start]) { $t1_start++; $t2_start++; }
	for($i = $t1_start; $i < $t1_end; $i++) if ($t1[$i]>'') $r1[$t1[$i]][] = $i;
	for($i = $t2_start; $i < $t2_end; $i++) if ($t2[$i]>'') $r2[$t2[$i]][] = $i;
	$a1 = $t1_start; $a2 = $t2_start;
	$actions = array();
	while ($a1 < $t1_end && $a2 < $t2_end) {
		if ($t1[$a1] == $t2[$a2]) { $actions[] = 4; $a1++; $a2++; continue; } 
		$best1 = $t1_end; $best2 = $t2_end;
		$s1 = $a1; $s2 = $a2;
		while(($s1 + $s2 - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2)) {
			$d = -1;
			foreach((array)@$r1[$t2[$s2]] as $n) if ($n >= $s1) { $d = $n; break; }
			if ($d >= $s1 && ($d + $s2 - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2)) { $best1 = $d; $best2 = $s2; }
			$d = -1;
			foreach((array)@$r2[$t1[$s1]] as $n) if ($n >= $s2) { $d = $n; break; }
			if ($d >= $s2 && ($s1 + $d - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2)) { $best1 = $s1; $best2 = $d; }
			$s1++; $s2++;
			}
		while ($a1 < $best1) { $actions[] = 1; $a1++; } 
		while ($a2 < $best2) { $actions[] = 2; $a2++; } 
		}
	while($a1 < $t1_end) { $actions[] = 1; $a1++; } 
	while($a2 < $t2_end) { $actions[] = 2; $a2++; } 
	$actions[] = 8;
	$op = 0;
	$x0 = $x1 = $t1_start; $y0 = $y1 = $t2_start;
	$out = array();
	foreach($actions as $act) {
		if ($act == 1) { $op |= $act; $x1++; continue; }
		if ($act == 2) { $op |= $act; $y1++; continue; }
    	if ($op > 0) {
			$xstr = ($x1 == ($x0+1)) ? $x1 : ($x0+1) . ",$x1";
			$ystr = ($y1 == ($y0+1)) ? $y1 : ($y0+1) . ",$y1";
			if ($op == 1) $out[] = "<br /><span class=diff>" . BOLTtranslate('Deleted line') . " $xstr: </span>";
			elseif ($op == 3) $out[] = "<br /><span class=diff>" . BOLTtranslate('Changed line') . " $xstr: </span>";
			while ($x0 < $x1) { $out[] = $t1[$x0]; $x0++; }   # deleted elems
			if ($op == 2) $out[] = "<br /><span class=diff>" . BOLTtranslate('Added line') . " $ystr: </span>";
			elseif ($op == 3) $out[] = '<span class=diff>' . BOLTtranslate('to') . '</span>';
			while ($y0 < $y1) { $out[] = $t2[$y0]; $y0++; }   # added elems
			}
		$x1++; $x0 = $x1;
		$y1++; $y0 = $y1;
		$op = 0;
		}
	$out[] = '';
	if (substr($out[0], 0, 4) == '<br />') $out[0] = substr($out[0], 4);
	if ($out == Array('')) return "<br /><span class=diff>" . BOLTtranslate('No changes made') . "</span>\n";
	else return join("\n",$out);
	}

function BOLTdisplay ($outarray='', $args=Array(), $zone='') {
## THE MAIN FUNCTION USED TO DISPLAY A SET OF PAGES ACCORDING TO A TEMPLATE/FMT PARAMETER. SETS UP SYSTEM OPTIONS AND THEN SENDS TO APPROPRIATE SUBFUNCTIONS. THE MAIN DIFFERENCE BETWEEN TEMPLATE AND FMT IS THAT MARKUP IN TEMPLATES ARE PROCESSED IMMEDIATELY FOR EACH PAGE AND ESCAPED. FMTS ARE RETURNED UNPROCESSED FOR LATER PROCESSING AS PART OF THE MAIN PAGE. FMTS ARE FASTER BUT CANNOT PROCESS MARKUPS PRIOR IN THE MARKUPTABLE.
	if (function_exists('myBOLTdisplay')) return myBOLTdisplay($outarray, $args, $zone);
	if (isset($args['count']) && $args['count'] != 'false') {
		if (strpos($args['count'], "-")) {
			$x = explode("-", $args['count']);
			$x[0] = $x[0] - 1;
			$x[1] = $x[1] - 1;
			}
		else {
			$x[0] = 0;
			$x[1] = $args['count'] - 1;
			}
		if (is_numeric($x[0]) && is_numeric($x[1])) {
			$i = 0;
			foreach ($outarray as $k => $kk) {
				if (($x[0] < $i && $i > $x[1]) || ($x[0] > $i && $i < $x[1])) unset($outarray[$k]);
				$i = $i + 1;
				}
			}
		}
	if (! is_array($outarray)) return;
	$template = $args['template'];
	$fmt = $args['fmt'];
	if ($template == 'count' || $fmt == 'count') return count($outarray);
	if ($template == 'csv' || $fmt == 'csv') return implode(',', $outarray);
	if ($template == 'list' || $fmt == 'list') return implode("\n", $outarray);
	if ($template == 'title' || $fmt == 'title') return BOLTdisplayFmt($outarray, "[[{+p}|+]]", $args, $zone);
	if ($fmt == 'toc') return BOLTdisplayTemplate($outarray, $fmt, $args, $zone);
	if ($fmt != '') return BOLTdisplayFmt($outarray, $fmt, $args, $zone);
	return BOLTdisplayTemplate($outarray, $template, $args, $zone);
	}

function BOLTdisplayFmt ($outarray='', $fmt='', $args=Array(), $zone='') {
## A SUBFUNCTION USED TO PROCESS FMT PARAMETER, CALLED BY BOLTDISPLAY.
	global $actionLink, $BOLTskin, $pageLink, $BOLTid;
	$join = $args['join'];
	if ($join == '') $join = "\n";
	if ($args['output'] == 'escape') $escape = true;
	if (BOLTfilter($fmt, 'page') != '') {
		$fmt2 = BOLTpageshortcuts($fmt);
		$templatePages = BOLTconfig('BOLTtemplatePages', 'template');
		if ($actionLink != '') $temp = BOLTloadpage("action.$actionLink#$fmt2");
		if ($temp == '') $temp = BOLTloadpage("$pageLink#$fmt2");
		if ($temp == '') $temp = BOLTloadpage("$templatePages.$fmt2.$BOLTskin");
		if ($temp == '') $temp = BOLTloadpage("$templatePages.$fmt2");
		if ($temp == '' && $fmt2 != $pageLink && BOLTexists($fmt2)) {
			if (BOLTauth($fmt2, $BOLTid, 'view')) $temp = BOLTloadpage($fmt2);
			else $fmt = '';
			}
		if ($temp != '') $fmt = $temp;
		$fmt = htmlspecialchars($fmt, ENT_NOQUOTES);
		$fmt = str_replace('[form', '[fo>rm', $fmt);
		}
//	if (strpos($fmt, "\n") === false && ! isset($args['join'])) $fmt = $fmt . "\n";
	foreach($outarray as $item) {
		$item = trim($item);
		if ($item === '') continue;
		$fmt_temp = $fmt;
		$p = explode('.', $item);
		$fmt_temp = str_replace('{+p0}', count($p), $fmt_temp);
		$fmt_temp = str_replace('{+p}', $item, $fmt_temp);
		foreach ($p as $i => $ii) {
			$check = '{+p' . ($i + 1) . '}';
			$fmt_temp = str_replace('{+p' . ($i + 1) . '}', $ii, $fmt_temp);
			}
		$fmt_temp = preg_replace('/\{\+p[0-9]{1}\}/', '', $fmt_temp);
		$out .= $fmt_temp . $join;
		}
	if (substr($out, - strlen($join)) == $join) $out = substr($out, 0, - strlen($join));
//	if ($args['markuptable'] == 'reload') $out = BOLTdomarkup($out, $pageLink, strtoupper($zone), $args['rules']);
	$out = BOLTstripslashes($out);
	if ($args['escape'] == 'true') BOLTescape($out);
	return $out;
	}

function BOLTdisplayTemplate ($outarray='', $template='', $args=Array(), $zone='') {
## A SUBFUNCTION USED TO PROCESS TEMPLATE PARAMETER, CALLED BY BOLTDISPLAY.
	global $pageLink, $BOLTvar, $actionLink, $BOLTskin, $BOLTid;
	$join = $args['join'];
	if ($join == '') $join = "\n";
	if ($args['output'] == 'escape') $escape = true;
	$templatePages = BOLTconfig('BOLTtemplatePages', 'template');
	if ($template === '' || $template == NULL) $template = BOLTloadpage("$templatePages.default");
	else {
		$template2 = BOLTpageshortcuts($template);
		if (BOLTfilter($template2, 'page') != '') {
			if ($actionLink != '') $temp = BOLTloadpage("action.$actionLink#$template2");
			if ($temp == '') $temp = BOLTloadpage("$pageLink#$template2");
			if ($temp == '') $temp = BOLTloadpage("$templatePages.$template2.$BOLTskin");
			if ($temp == '') $temp = BOLTloadpage("$templatePages.$template2");
			if ($temp == '' && $template2 != $pageLink && BOLTexists($template2)) {
				if (BOLTauth($template2, $BOLTid, 'view') == true) $temp = BOLTloadpage($template2);
				else $template = '';
				}
			if ($temp != '') $template = $temp;
			}
		}
	$template = htmlspecialchars($template, ENT_NOQUOTES);
	$template = str_replace('[form', '[fo>rm', $template);
 	$BOLTvar['$count_total'] = count($outarray);
	$zone = strtoupper($zone);
	if (is_array($args)) foreach ($args as $f => $v) $template = str_replace('$'.$f, $v, $template);
	foreach($outarray as $i => $ii) {
		$i = preg_replace('/(.*)(\<[0-9]+$)?/U', '$1', $i);
		$index[] = $i;
		$pages[] = $ii;
		}
	if (strpos($template, '[(template') !== false) {
		if (substr($template, -1) == "\n") $template = substr($template, 0, -1);
		$parts = explode("\n[(template", "\n$template");
		foreach ($parts as $p) {
			if ($p == '') continue;
			$index = trim(substr($p, 0, strpos($p, ')]')));
			$display[$index] = substr($p, strpos($p, ')]') + 2);
			}
		if (count($pages) == 0 || $pages == Array(0=>'')) {
			return BOLTescape(BOLTdomarkupTable($display['none'], $pageLink, $zone, $args['rules'])); 
			}
		$pagegroup = '';
		if (isset($display['first'])) {
			$BOLTvar['$count'] = 1;
			$first = BOLTdomarkupTable($display['first'], $pages[0], $zone, $args['rules']);
			if ($first != '') $out = $first . $join;
			}
		foreach ($pages as $i => $page) {
			$BOLTvar['$count'] = $i + 1;
			$BOLTvar['$prev'] = $pages[$i-1];
			$BOLTvar['$next'] = $pages[$i+1];
			$BOLTvar['$index'] = $index[$i];
			if (isset($display['group'])) {
				if ($pagegroup != substr($page, 0, strrpos($page, "."))) {
					$pagegroup = substr($page, 0, strrpos($page, "."));
					$group = BOLTdomarkupTable($display['group'], $page, $zone, $args['rules']);
					if ($group != '') $out .= $group . $join;
					}
				}
			if (isset($display[$i + 1])) $out .= BOLTdomarkupTable($display[$i + 1], $page, $zone, $args['rules']) . $join;
			else {
				$each = BOLTdomarkupTable($display['each'], $page, $zone, $args['rules']);
				if ($each != '') $out .= $each . $join;
				}
			}
		if (isset($display['last'])) {
			$last = BOLTdomarkupTable($display['last'], $page, $zone, $args['rules']);
			if ($last != '') $out .= $last;
			}
		}
	else {
		if (count($pages) == 0) return;
		foreach ($pages as $i => $page) {
			$BOLTvar['$count'] = $i + 1;
			$BOLTvar['$prev'] = $pages[$i-1];
			$BOLTvar['$next'] = $pages[$i+1];
			$BOLTvar['$index'] = $index[$i];
			$new = BOLTdomarkupTable($template, $page, $zone, $args['rules']);
			if ($new != '') $out .= $new . $join;
			}
		}
	if (substr($out, - strlen($join)) == $join) $out = substr($out, 0, - strlen($join));
	if ($args['escape'] == 'false') return $out;
	return BOLTescape(BOLTvspace($out));
	}

function BOLTdomarkup($content, $page='', $zone='', $rules='', $replace=true, $escape='') {
## THIS IS THE MAIN ENGINE WHICH TAKES A STRING OF MARKUPS AND RUNS THROUGH MARKUP TABLE. IT IS USED FOR EACH PAGE ZONE, AND EACH PAGE IN A TEMPLATE OUTPUT
	global $Token, $BOLTvar, $pageLink, $BOLTmsgOut, $BOLTzone, $BOLTautolines;
	$tempzone = $BOLTzone;
	$BOLTzone = $zone;
	if ($page == '') $page = $pageLink;
	else $page = BOLTpageshortcuts($page);
	if ($content == '[results]' && $query == '' && $lastquery == '') return;
	if (preg_match('/^~~([0-9]+)~~$/', $content) === 1) return $content;
	if ($escape == true) return $content;
	$content = htmlspecialchars($content, ENT_NOQUOTES);
	$content = str_replace('[form', '[fo>rm', $content);
	$out = BOLTdomarkupTable($content, $page, $zone, $rules, $replace);
	if ($BOLTautolines == 'true') $out = BOLTvspace($out, $zone);
	$BOLTzone = $tempzone;
	return BOLTurl2utf($out);
	}

function BOLTdomarkupTable($out, $page='', $zone='', $rules='', $replace=true) {
	global $MarkUpTable, $BOLTrules, $pageLink;
	if ($page == '') $page = $pageLink;
	if (function_exists('myBOLTmarkupRules')) $rules = myBOLTmarkupRules($page, $zone, $out, $rules);
	if (is_array($BOLTrules)) $myMarkUpTable = $BOLTrules;
	else $myMarkUpTable = $MarkUpTable;
	$out = preg_replace('/\{\*\:([^{}+=*:]+)\}/', '{'.$page.'*:$1}', $out); // base pages
	if ($replace == true) {
		$out = str_replace(Array('{+count','{+prev}','{+next}','{+index}'), Array('{count','{prev}','{next}','{index}'), $out);
		$out = preg_replace('/\{\+([^:{}+=*]+)\}/', '{'.$page.':$1}', $out); // template replacements
		$out = preg_replace('/\{\+:?([^{}+=*]+)\}/', '{'.$page.':$1}', $out);  
		}
	foreach($myMarkUpTable as $i => $order) {
		foreach ($order as $ii => $rule) {
			if ($rules != '') {
				 if (strpos(",$rules,", ",$i,") === false && strpos(",$rules,", ",$i:$ii,") === false) {
				 	continue;
					}
				 }
			$out = preg_replace($rule['pattern'], $rule['replace'], $out);
			}
		}
	return $out;
	}

function BOLTescape($x, $reverse=true) {
## USED IN VARIOUS PLACES TO PRESERVE SOME OUTPUT AND BLOCK ANY FURTHER MARKUP PROCESSING. SET REVERSE TO FALSE TO UNESCAPE A STRING OF TEXT.
	if ($x == '') return;
//	if ($x == "\n") return '<>';
	global $Token;
	if($reverse == false) {
		while (preg_match('/~~([0-9]+)~~/', $x) != 0) $x = preg_replace('/~~([0-9]+)~~/e', '$Token[$1]', $x);
		return $x;
		}
	$c = count($Token);
	$c = $c + 1;
	$Token[$c] = $x;
	return "~~$c~~";
	}

function BOLTexecute($BOLTarray, $auto=false) {
## THE MAIN FORM PROCESSING SCRIPT, ONCE APPROVED USING FUNCTION: BOLTSECURE. USE $auto=true TO DO FORM PROCESSING WITHOUT PAGE SUBMISSION (SEE SCRIPTS)
	if ($BOLTarray == Array()) return;
	global $BOLTarray, $BOLTsession, $msg, $pagesDir, $BOLTtoolmap, $pageLink, $configDir, $scriptPath, $target;
	$BOLTsessionCommands = BOLTattrs('session');
	$f = BOLTgetlink('', 'commands.php', '', $configDir);
	if (file_exists($f)) include_once($f);
	elseif (file_exists("$scriptPath/commands.php")) include_once("$scriptPath/commands.php");
	BOLTmsg('form_submit');
	if (empty($BOLTarray['nextpage'])) $BOLTarray['nextpage'] = $pageLink;
	$target = $pageLink;
	$auth = BOLTexists('site.auth.commands');
	foreach ($BOLTarray as $field => $value) {
		if ($value != $BOLTarray[$field]) $value = $BOLTarray[$field];
		if ($field != 'boltcontent') $value = preg_replace('/\{\=([=\:\\w]+)\}/e', 'BOLTfieldreplace("$1", $BOLTarray)', $value);
		if (substr($field, -4) == 'page') {
			if (strpos($value, '://') === false) $value = BOLTpageshortcuts($value);
			}
		if (function_exists('myBOLTformFilter')) $value = myBOLTformFilter($field, $value);
		if (strpos($field, "_")) $command = substr($field, 0, strpos($field, "_"));
		else $command = $field;
		$BOLTarray[$field] = $value;
// print_r("<hr>$field ($value)");
		if (substr($command, 0, 4) == 'bolt') $command = substr($command, 4);
		if ($BOLTtoolmap['x'][$command] != '') $command = $BOLTtoolmap['x'][$command];
		else $command = BOLTtranslate($command, '', 1);
		if ((function_exists("BOLTX$command")) && ($command == strtolower($command))) {
			if (strpos(" ,$BOLTsessionCommands,", ",$command,") !== false && isset($_POST[$command])) BOLTabort('invalid_post', "~$command");
			$BOLTcommand = "BOLTX$command";
			if ($auth == false) $value = $BOLTcommand($value, $field);
			elseif (BOLTauth($pageLink, $command, 'commands')) $value = $BOLTcommand($value, $field);
			else continue;
			}
		$BOLTarray[$field] = $value;
// print_r(" => $value)");
		}
// die();
//	$BOLTsession['MSG'] = $msg;
	if ($auto == true) return;
	BOLTredirect($BOLTarray['nextpage'] . $BOLTarray['passdata']);
	}

function BOLTexists($page, $dir='') {
## CHECKS IF FILE EXISTS IN PAGES DIRECTORY OR THE FARMS SYSTEM DIRECTORY
	if (function_exists('myBOLTexists')) return myBOLTexists($page, $dir);
	if ($page == '') return false;
	$fpage = BOLTfolders($page);
	global $systemPath, $pagesDir;
	if ($dir == $pagesDir) return file_exists("$dir/$fpage");
	if ($dir == 'system') return file_exists("$systemPath/$page");
	if ($dir != '') {
		if (substr($dir, -1) == '/') $dir = substr($dir, 0, -1);
		return file_exists("$dir/$page");
		}
	if (strpos($page, '#')) $page = substr($page, 0, strpos($page, '#'));
	$fpage = BOLTfolders($page);
	if (file_exists("$pagesDir/$fpage")) return true;
	if (file_exists("$systemPath/$page")) return true;
	return false;
	}

function BOLTfieldreplace($x, $myarray) {
## USED TO DO FIELD REPLACEMENTS AND TEMPLATE INSERTIONS
	global $BOLTadmin, $BOLTid, $BOLTmemberships;
	if (substr($x, 0, 1) == '=') return "\{$x}";
	if (! BOLTingroup('admin') && ! BOLTingroup('editor')) {
		$r1 = Array(' ? ', ' : ', ' , ');
		$r2 = Array(' &#63; ', ' &#58; ', ' &#44; ');
		}
	if (isset($myarray[$x])) return str_replace($r1, $r2, $myarray[$x]);
	if (strpos($x, ':')) {
		$i = substr($x, 0, strpos($x, ":"));
		$page = BOLTpageshortcuts($myarray[$i]);
		$field = substr($x, strpos($x, ":"));
		if (isset($myarray[$i])) return (str_replace($r1, $r2, BOLTvars("$page$field")));
		}
	return "{=$x}";
	}

function BOLTfilter($input, $type, $default='') {
## USED TO FILTER USER-CONTRIBUTED INPUTS OF VARIOUS TYPES. IF IT FAILS THE CORRESPONDING PATTERN CHECK IT RETURNS THE DEFAULT VALUE. DEFAULT FILTERS AVAILABLE: LETTERS, NUMBERS, PAGE, CSV, PARAMETER & MATH (SEE SOURCE)
	global $BOLTfilter;
	if ($type == '') return $default;
	if ($type == 'page') $input = BOLTutf2url($input);
	if (substr($type, 0, 1) != '/') {
		if (isset($BOLTfilter[$type])) $type = $BOLTfilter[$type];
		if (substr($type, 0, 1) != '/') $type = '/^[' . str_replace(Array('\\','^',']','/'), Array('\\\\','\^','\]','\/'), $type). ']+$/';
		}
	if (preg_match($type, $input) == 0) return $default;
	else return $input;		
	}
	
function BOLTfixdir($dir, $protect=true) {
## THIS FUNCTION CREATES DIRECTORIES AS NEEDED AND SETS HTACCESS PERMISSIONS
	if (! file_exists($dir)) {	
		mkdir($dir, 0777);
		clearstatcache();
		}
	if (substr(sprintf('%o', fileperms($dir)), -4) != '0777') {
//		chmod($dir, 0777);
		clearstatcache();
		}
	if (($protect == true) && (! file_exists("$dir/.htaccess"))) {
		$htaccess = "Order Deny,Allow\nDeny from all\n";
		$page = fopen("$dir/.htaccess", "wb");
	    fwrite($page, $htaccess);
	    fclose($page); 
		}
	return;
	}

function BOLTfolders($page, $htaccess=false) {
## THIS FUNCTION ALLOWS CERTAIN PAGES TO BE STORED IN SUBDIRECTORIES OF PAGES FOLDER. YOU MUST SET UP SITE.FOLDERS WITH A LIST OF SETTINGS LIKE COMMENTS: COMMENTS. CREATES FOLDERS IF NEEDED. USE $htaccess=true IF DON'T WANT HTACCESS CONTROL 
	global $pagesDir, $BOLTfolders, $BOLTsiteFolders;
	if (isset($BOLTsiteFolders[$page])) return $BOLTsiteFolders[$page] . $page;
	if (isset($BOLTfolders)) $contents = $BOLTfolders;
	else {
		$contents = BOLTloadpage('site.folders');
		$BOLTfolders = $contents;
		}
	$folders = explode("\n", $contents);
	foreach ($folders as $folder) {
		if (strpos($folder, ": ") === false) continue;
		else {
			$find = substr($folder, 0, strpos($folder, ": "));
			$replace = substr($folder, strpos($folder, ": ") + 2);
			}
		if (substr($page, 0, strlen($find) + 1) == $find . "." || $page == $find) {
			if ($htaccess === false) BOLTfixdir("$pagesDir/$replace");
			$BOLTsiteFolders[$page] = "$replace/";
			return "$replace/$page";
			}
		}
	$BOLTsiteFolders[$page] = '';
	return $page;	
	}

function BOLTfunc($function, $args, $zone='') {
	global $pageLink, $actionLink, $BOLTtoolmap, $Token;
	$function = strtolower($function);
	if ($args['stopwatch'] == 'true') {$m = microtime(); $t1 = substr($m, -10) . substr($m, 1, 6);}
	if ($BOLTtoolmap['f'][$function] != '') $function = $BOLTtoolmap['f'][$function];
	else $function = BOLTtranslate($function, '', 1);
	if (function_exists("BOLTF$function")) {
		$BOLTfunction = "BOLTF$function";
		if (BOLTauth($pageLink, $function, 'functions')) $value = $BOLTfunction($args, $zone);
		else {
			return;
//			$c = 0;
//			while (isset($msg["function_not_enabled_$c"])) {$c = $c + 1;}
//			BOLTabort("function_not_enabled_$c", "Function $1 not enabled for this page.~$function");
			}
		}
	if (isset($args['output'])) {
		if (preg_match('/^\~\~([0-9]+)\~\~$/', $value) == 1) $value = BOLTescape($value, false);
		switch($args['output']) {
			case 'false' : return; break;
			case 'source' : $value = str_replace("\n", '<br />', $value); break;
			case 'nolines' : $value = str_replace("\n", ' ', $value); break;
			case 'csv' : $value = str_replace("\n", ',', $value); break;
			}
		if (isset($escape) || $args['output'] == 'escape') $value = BOLTescape($value); 
		}
	if ($args['stopwatch'] == 'true') {
		global $BOLTstopWatchMsg;
		$m = microtime(); $t2 = substr($m, -10) . substr($m, 1, 6);
		$t = substr($t2 - $t1, 0, 6);
		$BOLTstopWatchMsg = $BOLTstopWatchMsg . "<br />&nbsp;&nbsp;&nbsp;Function $function took $t seconds";
		}
	$value = str_replace('[form', '[fo>rm', $value);
	return $value;
	}

function BOLTgetlines($out, $lines) {
## THIS SYSTEM FUNCTION IS USED BY INCLUDE & SOURCE TO RETRIEVE CERTAIN LINES AS IN LINES=5..10
	$outlines = explode("\n", $out);
	if (strpos($lines, '..') !== false) {
		$offset = substr($lines, 0, strpos($lines, '..'));
		if ($offset > 0) $offset = $offset - 1;
		$length = substr($lines, strpos($lines, '..') + 2) + 1;
		if ($length > 0) $length = $length - $offset - 1;
		}
	else {
		if ($lines > 0) $length = $lines;
		else $offset = $lines;
		}
	$outlines = array_slice($outlines, $offset, $length);
	return implode("\n", $outlines);		
	}

function BOLTgetlink($start='', $end='', $myArray='', $path='') { 
## A SECONDARY FUNCTION TO GET HIERARCHICAL LINKS (SEE GETLINK FUNCTION). THIS IS ONLY USED BY SKINS I BELIEVE AND WILL LIKELY BE REMOVED IN 3.XX
	if (function_exists(myBOLTgetlink)) return myBOLTgetlink($start, $end, $myArray, $path);
	global $pageArray, $BOLTskin;
    if ($myArray == '') $tempArray = $pageArray; 
	else $tempArray = $myArray;
	if ($start != '') $start = "$start.";
	$out='';
	for ($i = count($tempArray); $i >= 0; $i = $i - 1) { 
		if ($i == 0) $link = $start . "$end.$BOLTskin"; 
		else $link = $start . implode(".", $tempArray) . ".$end.$BOLTskin"; 
		if ($path != '') { 
			if (file_exists("$path/$link")){ $out="$path/$link"; break;} 
			} 
		elseif (BOLTexists($link)) { $out=$link; break;} 
		array_pop($tempArray); 
		}
	if ($out != '') return rtrim($out, '.');
	if ($end == 'skin') $BOLTskin = '';
    if ($myArray == '') $tempArray = $pageArray; 
	else $tempArray = $myArray;
	for ($i = count($tempArray); $i >= 0; $i = $i - 1) { 
		if ($i == 0) $link = $start . $end; 
		else $link = $start . implode(".", $tempArray) . ".$end"; 
		if ($path != '') { 
			if (file_exists("$path/$link")){ $out="$path/$link"; break;} 
			} 
		elseif (BOLTexists($link)) { $out=$link; break;} 
		array_pop($tempArray); 
		}
	return rtrim($out, '.');
	}

function BOLTgetskin() { 
## THIS FUNCTION GETS HIERARCHICAL LINKS USED FOR MANY BOLTWIRE FUNCTIONS
	global $pagesDir, $BOLTskin, $systemPath, $skinPath, $msg, $BOLTskin;
	if (BOLTexists("code.skin.$BOLTskin")) return;
	$BOLTcodePages = BOLTconfig('BOLTcodePages', 'code');
	if (file_exists("$skinPath/$BOLTskin/$BOLTcodePages.skin.$BOLTskin")) {	
		$exclude = ".html,.css,.jpg,.gif,.png,.db,.htaccess,.txt,.php,.js";
		$files = BOLTlistpages(NULL, "$skinPath/$BOLTskin");
		foreach ($files as $file) {
			$type = substr($file, strrpos($file, '.'));
			if (strpos(",$exclude,", $type) === false) copy("$skinPath/$BOLTskin/$file", "$pagesDir/$file");
			}
		clearstatcache();
		}
    }

function BOLTgetzones($zone) {
## REPLACE SKIN ZONE MARKERS [[ZONE]] WITH CONTENT: GETS LINK, LOADS PAGE, DOES MARKUP
	if (function_exists('myBOLTgetzones')) return myBOLTgetzones($zone);
	global $pagesDir, $pageLink, $pageShow, $BOLTpage, $BOLTid, $BOLTvar, $BOLTpluginHeader, $BOLTtime, $formmemory, $BOLTreplaceTable, $actionLink;
//	$zone = strtolower($zone);
	if (BOLTconfig("BOLTnozone:$zone") !== '') {
		if (BOLTpageCheck(BOLTconfig("BOLTnozone:$zone"))) return;
		}
	if ($_GET['action'] == 'print' || $_GET['print'] === 'true') {
		if (BOLTconfig("BOLTnoprintzone:$zone") !== '') {
			if (BOLTpageCheck(BOLTconfig("BOLTnoprintzone:$zone"))) return;
			}
		if ($_GET[$zone] == 'false') return;
		}
	if ($zone == 'header' || $zone == 'footer') {
		if (strpos(',,' . BOLTconfig('BOLTsimpleMain', 'print,view,cache') . ',', ",$_GET[action],") === false) return;
		if (BOLTauth($pageLink, $BOLTid, 'view') !== true) return;
		}
	if (strtolower($zone) == 'main') {
//		if (isset($_GET['help'])) {
//			if (BOLTconfig('BOLThelpSystem', 'true') == 'true') return BOLTdomarkup(BOLTloadpage('site.help'));
//			}
		$formmemory = '';
		$link = $pageLink;
		if (isset($_GET['action'])) { 
			$actionLink = substr(BOLTpageshortcuts("a.$_GET[action]"), 2);
			if (BOLTconfig('BOLTlanguage') != '') {
				$temp = BOLTgetlink('action-'.BOLTconfig('BOLTlanguage'), $actionLink);
				if (BOLTexists($temp)) $link = $temp;
				}
			if ($link == $pageLink) {
				$temp = BOLTgetlink('action', $actionLink);
				if (BOLTexists($temp)) $link = $temp;
				}
			if ($link == '') $link = $pageLink;
			}
		if (($link == $pageLink) && (!BOLTexists($link))) {
			$link = BOLTgetlink('action', 'missing');
			if (BOLTconfig('serverHeaders') == 'true') header('HTTP/1.1 404 Not Found');
			$BOLTpluginHeader[] = '<meta name="robots" content="noindex">';
			}
		if (BOLTauth($link, $BOLTid, 'view') !== true) {
			$link = BOLTgetlink('action', 'blocked');
			if (BOLTconfig('serverHeaders') == 'true') header('HTTP/1.1 403 Forbidden');
			$BOLTvar['$action'] = $link;
			}
		$pageShow = $link;
		}
	else $link = BOLTgetlink('', $zone);
	$BOLTcachedZones = BOLTconfig('BOLTcacheZones');
	if (strpos(",$BOLTcachedZones,", ",$zone,") !== false) {
		if ($_GET['action'] == '' && $_POST == Array ()) {
			$BOLTzonesDir = BOLTconfig('BOLTzonesDir', 'zones');
			if (file_exists("$BOLTzonesDir/$link")) {
				if (! BOLTexists($link)) unlink("$BOLTzonesDir/$link");
				else {
					if (BOLTconfig('BOLTcacheLimit') > 0 && BOLTconfig('BOLTcacheLimit') < time() - filemtime("$BOLTzonesDir/$link")) {
						unlink("$BOLTzonesDir/$link");
						}
					elseif (filemtime("$BOLTzonesDir/$link") > filemtime("$pagesDir/$link")) {
						BOLTstopWatch("Cached '$link' retrieved");
						return file_get_contents("$BOLTzonesDir/$link");
						}
					}
				}
			}
		if ($_GET['action'] == 'view' && file_exists("$BOLTzonesDir/$link")) unlink("$BOLTzonesDir/$link");
		}
	$out = BOLTloadpage($link);
	$p1 = substr($link, 0, strpos($link, "."));
	if ($p1 == BOLTconfig('BOLTcodePages', 'code') || $p1 == BOLTconfig('BOLTtemplatePages', 'template')) {
		if ($link != 'code.embed') $out = "<code>\n$out\n</code>";
		}
	if (is_array($BOLTreplaceTable['$zone'])) $out = strtr($out, $BOLTreplaceTable['$zone']);
	$out = BOLTdomarkup($out, '', $zone, '', false);
//	$out = str_replace('<>', "\n", $out);
	if (strpos(",$BOLTcachedZones,", ",$zone,") !== false) {
		global $BOLTnoCache;
		if ($BOLTnoCache[$link] == false) {
			$BOLTzonesDir = BOLTconfig('BOLTzonesDir', 'zones');
			if (! file_exists($BOLTzonesDir)) BOLTfixdir($BOLTzonesDir);
			$cachePage = fopen("$BOLTzonesDir/$link", "wb");
			$cacheOut = $out;
			while (preg_match('/\~\~([0-9]+)\~\~/', $cacheOut) == 1) $cacheOut = BOLTescape($cacheOut, false);
			$cacheOut = preg_replace("/\<div class\=\'message\'\>.*?\<\/div\>/", '', $cacheOut);
		    fwrite($cachePage, $cacheOut);
		    fclose($cachePage); 
			clearstatcache();
			}
		}
	return $out;
	}

function BOLTindex($args, $zone='') {
## HERE IS THE MAIN MARKUP FUNCTION THAT HANDLES INDEXING. ALLOWED PARAMETERS INCLUDE CSV LIST OF PAGES IN POSITION 1, AND OPTIONAL ALTINDEX. IF NO PAGES SPECIFIED, USES CONFIG SETTINGS TO LOAD LIST FROM THE SITE INDEX LIST.
	if (function_exists('myBOLTindex')) return myBOLTindex($args, $zone);
	global $pagesDir, $systemPath;
	$batch = BOLTconfig('BOLTindexBatch', '25');
	$BOLTindexExclude = BOLTconfig('BOLTindexExclude', 'code*,template*,action*');
	$BOLTindexDir = BOLTconfig('BOLTindexDir', 'indexes');
	$loginPages = BOLTconfig('BOLTloginPages', 'login');
	$BOLTindexPlus = BOLTconfig('BOLTindexPlus', 'page,title');
	if (isset($args['altindex'])) {
		$BOLTindexFile = $args['altindex'] . '.index';
		$BOLTindexList = 'site.index.' . $args['altindex'];
		}
	else {
		$BOLTindexFile = BOLTconfig('BOLTindexFile', 'search.index');
		$BOLTindexList = BOLTconfig('BOLTindexList', 'site.index.list');
		}
	$allPages = implode(',', array_unique(BOLTlistpages()));
	BOLTdefault($BOLTindexStrippedChars, Array ('!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', "\n", "\r", "\t"));
// retrieve already indexed data
	if (! file_exists($BOLTindexDir)) {
		BOLTfixdir($BOLTindexDir);
		BOLTsavepage($BOLTindexList, implode("\n", BOLTsearchPageList(Array())), '', false, false);			
		}
	$searchindex = BOLTloadpage("$BOLTindexFile", $BOLTindexDir);
	if ($searchindex != '') {
		$lines = explode("\n", $searchindex);
		foreach ($lines as $line) {
			if (strpos($line, ':') === false) continue;
			$page = substr($line, 0, strpos($line, ':'));
			if (strpos(",$allPages,", ",$page,") === false) continue; 
			$indexPage[$page] = $line;
			}
		}
// determine which pages to index
	if (isset($args[1])) $indexArray = explode(',', $args[1]);
	elseif (isset($args['pages']) || isset($args['group']) || isset($args['exclude'])) {
		$indexArray = BOLTsearchPageList($args, $zone);
		$noindexList = false;
		}
	elseif (! BOLTexists($BOLTindexList)) return;
	else {
		$tempArray = explode("\n", trim(BOLTloadpage($BOLTindexList)));
		$indexArray = array_slice($tempArray, 0, $batch);
		$noindexArray = array_slice($tempArray, $batch, count($tempArray));
		$noindexList = "\n" . implode("\n", $noindexArray);
		}
	
// begin indexing each page in list...
	foreach ($indexArray as $p) {
		if (! BOLTpageCheck($BOLTindexExcludePages, $p)) continue;
		$content = BOLTloadpage($p, '', 'data');
		if ($content == '') {
			unset($indexPage[$p]);
			continue;
			}
		if (strpos($content, "\n~data~\n") !== false) {
			$data = substr($content, strpos($content, "\n~data~\n") + 8);
			if (strpos($BOLTindexPlus, 'title') !== false) {
				if (strpos($content, "~\ntitle: ") !== false) {
					$title = substr($content, strpos($content, "~\ntitle: ") + 9);
					$title = substr($title, 0, strpos($title, "\n"));
					$content = "$title $content";
					}
				}
			if (strpos($BOLTindexPlus, 'page') !== false) $content = BOLTurl2utf($p) . " $content ";
			if (strpos($BOLTindexPlus, 'data') === false) $content = substr($content, 0, strpos($content, "\n~data~\n"));
			}
// index links
		preg_match_all('/\[\[([^{}:&#|@\/\]]+)(\&|\#|\||\])/', $content, $links); 
		$linksArray = array_unique($links[1]);
		$mylinks = implode("<>", $linksArray);
		$mylinks = BOLTutf2url(str_replace('~', "$loginPages.", $mylinks));
// indext text
		$content = preg_replace('/\[(.*?)\]/', ' ', $content);
		$content = preg_replace('/\{(.*?)\}/', ' ', $content);
		$content = preg_replace('/\<(.*?)\>/', ' ', $content);
//		$content = str_replace('&lt;', ' ', $content);
		$content = str_replace('~data~', '', $content);
		$content = str_replace($BOLTindexStrippedChars, ' ', $content);
		$textArray = array_unique(explode(" ", $content));
		if (count($textArray) > 1 || $textArray[0] != '') $mytext = ' ' . implode(" ", $textArray) . ' ';
		else $mytext = '';
// index data
		if ($data != '') {
			$d = explode("\n~\n", $data);
			$dataArray = Array();
			foreach ($d as $dd) {
				if ($dd == '') continue;
				$f = substr($dd, 0, strpos($dd, ': '));
				$v = substr($dd, strpos($dd, ': ') + 2);
				if (strpos($v, "\n") !== false) $v = substr($v, 0, strpos($v, "\n"));
				if (strlen($v) > 40) $v = substr($v , 0, 40);
				$dataArray[] = "$f=$v";
				}
			$mydata = implode("<>", $dataArray);
			}
		$indexPage[$p] = "$p:$mytext:$mylinks:$mydata";
		$indexdisplay .= "\n$p";
		}
// final steps
	if (!is_array($indexPage)) return;
 	sort($indexPage);
	$outindex = implode("\n", $indexPage);
	$outindex = str_replace('  ', ' ', $outindex);
	if ($outindex != $searchindex) {
		$handle = fopen("$BOLTindexDir/$BOLTindexFile", "wb");
		fwrite($handle, $outindex);
		fclose($handle);
		}
	if ($noindexList !== false) BOLTsavepage($BOLTindexList, $noindexList, '', false, false);
	return trim($indexdisplay);
	}

function BOLTindexQuery($outarray, $args) {
## THIS FUNCTION OPENS AN INDEX AND STRIPS OUT THE APPROPRIATE LINES FOR SEARCHING
	if (empty($outarray)) return Array();
	$BOLTindexDir = BOLTconfig('BOLTindexDir', 'indexes');
	if ($index == '') $index = 'search';
	$location = "$BOLTindexDir/$index.index";
	if (file_exists($location)) {
		$handle = fopen($location, "rb");
		$contents = fread($handle, filesize($location));
		fclose($handle);
		}
	preg_match_all('/^([-_a-z0-9.%]+)\: (.*)?/m', $contents, $matches);
	$tempIndex = array_combine($matches[1], $matches[2]);
	foreach ($outarray as $page) {
		if (isset($tempIndex[$page])) $out[$page] = $tempIndex[$page]; 
		}
	if (empty($out)) return Array();
	return $out;
	}

function BOLTinfoVar($page, $var, $default='', $auth=false, $pattern='') {
## THIS FUNCTION RETRIEVES AN "INFO" VAR'S VALUE FROM ACTUAL PAGE TEXT (OR $DEFAULT IF NOT FOUND). INFO VALUES CANNOT HAVE LINE BREAKS (DEFAULT) AND ARE OF THE FORMAT FIELD: VALUE. NOTE THE PATTERN CAN BE CHANGED. NORMALLY READ PERMISSION ONLY IS REQUIRED
	global $BOLTinfoCache, $BOLTinfoVarPat, $BOLTid;
	if (!BOLTauth($page, $BOLTid, 'view') && $auth) return;
	$var = strtolower(BOLTutf2url($var));
	if (isset($BOLTinfoCache[$page][$var])) return $BOLTinfoCache[$page][$var]; 
	if ($pattern == '') {
		if ($BOLTinfoVarPat == '') $pattern = '/^(\S+)\: (.+)?/m';
		else $pattern = $BOLTinfoVarPat;
		}
	$content = htmlspecialchars(BOLTloadpage($page), ENT_NOQUOTES); 
	preg_match_all($pattern, $content, $matches);
	$codeSnippets = BOLTconfig('BOLTcodePages', 'code') . '.snippets';
	if (substr($page, 0, strlen($codeSnippets)) == $codeSnippets) {
		preg_match_all('/\[\[\#([-_a-zA-Z0-9]+)\]\](.+)\[\[\#/sU', $content, $matches2);
		$matches[1] = array_merge($matches[1], $matches2[1]);
		$matches[2] = array_merge($matches[2], $matches2[2]);
		}
	foreach ($matches[1] as $i => $ii) {
		$ii = strtolower(BOLTutf2url($ii));
		if ($BOLTinfoCache[$page][$ii] == '') $BOLTinfoCache[$page][$ii] = preg_replace('/\/\=(.*?)\=\//se', 'BOLTescape(BOLTstripslashes("$1"))', trim($matches[2][$i]));
		}
	if ($BOLTinfoCache[$page][$var] != '') return $BOLTinfoCache[$page][$var];
	if ($page == BOLTconfig('BOLTmessages', 'site.messages')) {
		$var2 = $BOLTinfoCache[$page][substr($var, 0, strrpos($var, "_"))];
		if (is_numeric(substr($var, strrpos($var, "_") + 1))) return $var2;
		}
	return $default;
	}

function BOLTingroup($group, $id='', $new=true) {
	global $BOLTid, $pagesPath, $BOLTmemberships, $BOLTadmin;
	if ($id == '') $id = $BOLTid;
	if ($id == '') return false;
	$id = strtolower(BOLTutf2url($id));
	if (strpos(" ,$BOLTadmin,", ",$id,") !== false && $BOLTadmin != '') return true;
	$group = strtolower($group);
	if ($id == $BOLTid && $new) return (strpos(",$BOLTmemberships,", ",$group,") !== false);
	$groupPage = BOLTconfig('BOLTgroupPages', 'group') . ".$group";
	$groupList = strtolower(BOLTutf2url(BOLTloadpage($groupPage)));
	if ($groupList == '') return false;
	return (strpos("\n$groupList\n", "\n$id\n") !== false);
	}

function BOLTlistpages($pat=NULL, $dir='', $folder='') {
## RETURNS A LIST OF PAGES MATCHING A GIVEN PATTERN
//	$pat = str_replace('&#36;', '$', $pat);
	global $systemPath, $pluginPath, $pagesDir;
	if ($dir == '') $mydir = $pagesDir;
	else $mydir = $dir;
	if ($folder != '') $mydir = $mydir . "/$folder";
	if ($dir != 'system') {
		if ($mydir == 'plugins') $mydir = $pluginPath;
		if (file_exists($mydir) !== false) {		
			if ($handle = opendir($mydir)) {
				while (false !== ($file = readdir($handle))) {
					if (substr($file, 0, 1) == ".") continue;
					if (is_dir("$mydir/$file")) {
						$handle2 = opendir("$mydir/$file");
						while (false !== ($file2 = readdir($handle2))) {
							if (($file2 == ".") || ($file2 == "..") || ($file2 == ".htaccess")) continue;
							if (($pat != NULL) && (! preg_match($pat, $file2))) continue;			
					        $list[] = $file2;
							}
						}
					else {
						if (($pat != NULL) && (! preg_match($pat, $file))) continue;
				        $list[] = $file;
						}
				    }
				closedir($handle);
				}
			}
		}
	if ($dir == '' || $dir == 'system') {
		$dir = $systemPath;
		if ($handle = opendir($dir)) {
	    	while (false !== ($file = readdir($handle))) {
				if (($pat != NULL) && (! preg_match($pat, $file))) continue;
				if (($file == ".") || ($file == "..") || ($file == ".htaccess")) continue;
	    	    if ($file != 'barn') $list[] = $file;
			    }
			closedir($handle);
			}
		}
	if (is_array($list)) {
		$list = array_unique($list);
		sort($list);
		}
	return $list;
	}

function BOLTloadpage($page, $dir='', $data='', $auth=false) {
## LOADS PAGE AT $LOCATION (PAGES/FILE NAME), RETURNS CONTENTS. SET $DATA TO 'data' TO RETRIEVE DATA WITH PAGE TEXT
	if (function_exists('myBOLTloadpage')) return myBOLTloadpage($page, $dir, $data, $auth);
	if ($auth) {
		global $BOLTid;
		if (BOLTauth($page, $BOLTid, 'view') == false) return;
		}
	if ($page == '') return;
	global $systemPath, $pagesDir, $BOLTconflict, $BOLTvar, $BOLTpageStore;
	if (strpos($page, "#") !== false) {
		$anchor = BOLTurl2utf(substr($page, strpos($page, "#")));
		$page = substr($page, 0, strpos($page, "#"));
		}
	if ($page != 'site.config' && $page != 'site.folders') {
		$page = strtolower(BOLTutf2url($page));
		$fpage = BOLTfolders($page);
		}
	else $fpage = $page;
	$BOLTconflict[$page] = time();
	if ($dir != '') {
		if (file_exists("$dir/$page")) $location = "$dir/$page";
		else return;
		if ($dir == BOLTconfig('BOLTstampsDir', 'stamps')) $page = "$page*";
		}
	elseif (file_exists("$pagesDir/$fpage")) $location = "$pagesDir/$fpage";
	elseif (file_exists("$systemPath/$page")) $location = "$systemPath/$page";
	else return;
	if ($BOLTpageStore[$page] == '' && filesize($location) > 0) {
		$handle = fopen($location, "rb");
		$contents = fread($handle, filesize($location));
		fclose($handle);
		$BOLTpageStore[$page] = str_replace(Array("\r\n", "\r"), "\n", $contents);
		}
	$out = $BOLTpageStore[$page];
	if ($data != 'data' && strpos($out, "\n~data~\n") !== false) {
		$out = substr($out, 0, strpos($out, "\n~data~\n"));
		$out = str_replace('&#126;', '~', $out);
		}
	if (isset($anchor)) {
		if ($anchor == '#') {
			if (strpos($out, '[[#') !== false) return substr($out, 0, strpos($out, '[[#'));
			return $out;
			}
		elseif (preg_match('/\[\['.$anchor.'(\|.+)?\]\]/', $out, $matches) == 1) {
			$out = substr($out, strpos($out, $matches[0]) + strlen($matches[0]));
			if (strpos($out, "[[#") !== false) return substr($out, 0, strpos($out, "[[#"));
			return $out;
			}
		return;
		}
	return $out;
	}

function BOLTlog($content, $target, $delimiter="\n", $flags='') {
## THIS IS THE MAIN SCRIPT USED BY THE LOG COMMAND/FUNCTION MARKUPS. THE OTHER FUNCTIONS PREPARE THE PARAMETERS, THIS ONE DOES THE ACTUAL WORK. FLAGS INCLUDE DELETE/REMOVE, TRIM=5 (MAX), TOP (BOTTOM DEFAULT), SORT, UNIQUE, LINE=3 (REPLACE 3RD LINE)
	global $msg;
	if ($delimiter == 'false') $delimiter = '';
	else $content = str_replace($delimiter, " ", $content);
	if (strpos($flags, 'lowercase') !== false) $content = strtolower($content);
	$source = BOLTloadpage($target);
	$flags = str_replace('delete', 'remove', $flags);
	if (strpos($flags, "remove") !== false && $content != '') {
		if ($source == $content) $source = '';
		$source = str_replace("$delimiter$content", '', $source);
		$source = str_replace("$content$delimiter", '', $source);
		}
	elseif (strpos($flags, "line=") === false) {
		if (strpos($flags, "top") !== false) $source = "$content$delimiter$source";
		else {
			if ($source == '') $source = $content;
			else $source = "$source$delimiter$content";
			}
		}
	if (strpos($flags, 'sort') !== false || strpos($flags, 'trim=') !== false || strpos($flags, 'unique') !== false || strpos($flags, 'line=') !== false) {
		if ($delimiter != '') {
			$editlist = explode ($delimiter, $source);
			if ($editlist[count($editlist) - 1] == '') array_pop($editlist);
			if (strpos($flags, 'sort') !== false) natcasesort($editlist);
			if (strpos($flags, 'sort') !== false || strpos($flags, 'unique') !== false) $editlist = array_unique($editlist);
			if (strpos($flags, 'reverse') !== false) $editlist = array_reverse($editlist);
			if (strpos($flags, 'trim') !== false) {
				$trim = substr($flags, strpos($flags, 'trim=') + 5);
				if (strpos($trim, ',') !== false) $trim = trim(substr($trim, 0, strpos($trim, ',')));
				if (count($editlist) > $trim) $editlist = array_slice($editlist, 0, $trim );	
				}
			if (strpos($flags, 'line=') !== false) {
				$line = substr($flags, strpos($flags, 'line=') + 5);
				if (strpos($line, ',') !== false) $line = trim(substr($line, 0, strpos($line, ',')));
				if ($line != 0) $editlist[$line - 1] = $content;
				}
			$source = implode($delimiter, $editlist);
			}
		}
	if ($delimiter != '') $source = str_replace("$delimiter$delimiter", $delimiter, $source);
	$source = str_replace('\n', "\n", $source);
	if ($source == '') $source = ' ';
	$source = str_replace(Array('&amp;', '&lt;', '&gt;'), Array('&', '<', '>'), $source);
	BOLTsavepage($target, $source, '', false);
	return;
	}

function BOLTmakepage() {
## THIS FUNCTION FINDS THE SKIN, LOADS IT AND REPLACES ZONES, IE MAKES THE PAGE
	if (function_exists('myBOLTmakepage')) return myBOLTmakepage();
	BOLTprocess('pre');
	global $BOLTmakeHTML, $pageLink, $pageArray, $scriptURL, $pagesDir, $BOLTvar, $BOLTinput, $BOLTconflict, $BOLTskin, $skinPath;
	global $BOLTpluginStyles, $BOLTpluginHeader, $BOLTpluginBody, $BOLTserverHeaders, $BOLTfieldKey, $BOLTreplaceTable, $BOLTmsgOut, $query, $lastquery;
	$BOLTcodePages = BOLTfolders(BOLTconfig('BOLTcodePages', 'code'));
	if (function_exists('myBOLTchooseSkin')) $skin = myBOLTchooseSkin();
	else {
		if ($_GET['action'] == 'print') {
			$BOLTskin = 'print';
			if (BOLTconfig('BOLTautoPrint') != 'false') BOLTreplace('<body', '<body onload=\'window.print();\'', 'HTML');
			}
		elseif ($pageArray[0] == 'rss') {
			if (! isset($_GET['action'])) $BOLTskin = 'rss';
			}
		if (! BOLTexists("$BOLTcodePages.skin.$BOLTskin")) BOLTgetSkin();
		$skin = BOLTgetlink($BOLTcodePages, 'skin');  // getlink can reset $BOLTskin if skin not found...
		if ($BOLTskin != '') {
			if (file_exists("$skinPath/$BOLTskin/skin.php")) include_once("$skinPath/$BOLTskin/skin.php"); 
			}
		$BOLTvar['$skin'] = $BOLTskin;
		}
	$out = BOLTloadpage($skin);
	if (is_array($BOLTreplaceTable['SKIN'])) $out = strtr($out, $BOLTreplaceTable['SKIN']);
	$out = preg_replace('/\<\<([-_a-z0-9]+)\>\>/ie', "BOLTloadpage(BOLTgetlink('".$BOLTcodePages."', $1))", $out);
	$out = preg_replace('/(\$\$|\&\#36\;\&\#36\;)([-_a-z0-9]+)(\:[-_a-z0-9\.]+)?/ie', "BOLTMsnippets('$2', '$3')", $out);
	$out = preg_replace('/\=\=(.*?)\=\=/e', 'BOLTdomarkup("$1", $pageLink, "SKIN")', $out);
	$out = preg_replace('/\[\[([-_a-z0-9]+)\]\]/ie', "BOLTgetzones('$1')", $out);
	while (preg_match('/\~\~([0-9]+)\~\~/', $out) == 1) $out = BOLTescape($out, false);
	$out = preg_replace('/\[messages( [-_a-z0-9]+)?\]/ie', 'BOLTmessages("$1")', $out);
//	$out = str_replace(Array('%5Bmessages', '%5Bresults'), Array('[messages', '[results'), $out);
		if ($query == '') $myquery = $lastquery;
		else $myquery = $query;
		$out = str_replace('[results]', BOLTescape($myquery, false), $out);
$out = str_replace(Array('%5Bmessages', '%5Bresults'), Array('[messages', '[results'), $out);
	if (isset($BOLTpluginStyles)) $out = str_replace('--></style>', implode($BOLTpluginStyles, "\n") . "\n--></style>", $out);
	if (isset($BOLTpluginHeader)) $out = str_replace('</head>', implode($BOLTpluginHeader, "\n") . "\n</head>", $out);
	if (isset($BOLTpluginBody)) $out = str_replace('</body>', implode($BOLTpluginBody, "\n") . "\n</body>", $out);
	if (is_array($BOLTreplaceTable['HTML'])) $out = strtr($out, $BOLTreplaceTable['HTML']);
	if (BOLTconfig('BOLTcacheHTML', 'false') == 'true') {
		global $BOLTnoCache;
		if ($BOLTnoCache[$pageLink] == false) {
			if ($_GET['action'] == '' && $pageArray[0] != 'action' && $_POST == Array()) {
				$noCacheGroup = BOLTconfig('BOLTnocachegroup');
				if ($noCacheGroup == '' || $_COOKIE['cache'] == '' || strpos($noCacheGroup, $_COOKIE['cache']) !== false) {
					$BOLThtmlDir = BOLTconfig('BOLThtmlDir', 'html');
					if (! file_exists($BOLThtmlDir)) BOLTfixdir($BOLThtmlDir);
					$page = fopen("$BOLThtmlDir/$pageLink.html", "wb");
					$cacheOut = preg_replace("/\<div class\=\'message\'\>.*?\<\/div\>/", '', $out);
				    fwrite($page, $cacheOut);
				    fclose($page); 
					clearstatcache();
					}
				}
			}
		}
	session_start();
	$_SESSION[$BOLTfieldKey]['FORM'][$pageLink] = $BOLTinput;
	$_SESSION[$BOLTfieldKey]['CONFLICT'] = $BOLTconflict;
	session_write_close();
	$delayRobots = BOLTconfig('BOLTdelayRobots', 0);
	if (is_numeric($delayRobots) && $delayRobots > 0) {
		if(filemtime("$pagesDir/" . BOLTfolders($pageLink)) + $delayRobots > time()) $out = str_replace(Array('</head>', '<HEAD>'), "<META NAME='ROBOTS' CONTENT='NOINDEX'>\n</head>", $out);
		}
	BOLTprocess('post');
	BOLTstopWatch('Page Creation Complete');
	if (is_array($BOLTserverHeaders)) {
		foreach($BOLTserverHeaders as $h) header($h);
		}
	return $out;
	}

function MarkUp($order, $rule, $pattern='', $replace='', $altTable=false) {
## THIS FUNCTION IS CALLED FOR EACH MARKUP DEFINITION AND CREATES THE $MARKUPTABLE. TO CHANGE AN EXISTING MARKUP RULE DO:  MarkUp('order', 'rule', '/pattern/', 'output'); TO DELETE AN EXISTING MARKUP RULE DO:  MarkUp('order', 'rule', ''); IT ALLOWS FINE TOOTHED CONTROL OF MARKUP TABLE USING 'newrule < oldrule' SYNTAX FOR RULE. TO VIEW DEFAULT MARKUP TABLE DO HELP=MARKUPTABLE
	global $MarkUpTable, $BOLTaltMarkUpTables;
	if ($altTable !== false) {
		$BOLTaltMarkUpTables[$altTable][$order][$rule]['pattern'] = $pattern;
		$BOLTaltMarkUpTables[$altTable][$order][$rule]['replace'] = $replace;
		return;
		}
	if (strpos($rule, '<') !== false) {
		$new = trim(substr($rule, 0, strpos($rule, '<')));
		$rule = trim(substr($rule, strpos($rule, '<') + 1));
		$array = $MarkUpTable[$order];
		foreach ($array as $f => $v) {
			if ($f != $rule) $array2[$f] = $MarkUpTable[$order][$f];
			else {
				$array2[$new]['pattern']  = $pattern;
				$array2[$new]['replace']  = $replace;
				$array2[$f] = $MarkUpTable[$order][$f];
				}
			}
		$MarkUpTable[$order] = $array2;
		}
	elseif ($pattern == '')	unset($MarkUpTable[$order][$rule]);
	else {
		$MarkUpTable[$order][$rule]['pattern'] = $pattern;
		$MarkUpTable[$order][$rule]['replace'] = $replace;
		}
	}

function BOLTmessages($id='') {
## PREPARES MESSAGES FOR FINAL OUTPUT, CHECKING FORM AND SITE.MESSAGES CUSTOMIZATIONS
	global $BOLTsession, $pageLink;
	$msg = $BOLTsession['MSG'];
	if ($id != '') {
		$id = trim($id);
		if ($id == '') $id = 'warn';
		if ($msg[$id] != '') return "<span class='messageid'>$msg[$id]</span>";
		else return;
		}
	if (count($msg) == 0) return;
	$messagePage = BOLTconfig('BOLTmessages', 'site.messages');
	foreach ($msg as $mi => $mv) {
		if (strpos($mv, '~') !== false) {
			$data1 = substr($mv, strpos($mv, '~') + 1);
			$mv = substr($mv, 0, strpos($mv, '~'));
			if (strpos($data1, '~') !== false) {
				$data2 = substr($data1, strpos($data1, '~') + 1);
				$data1 = substr($data1, 0, strpos($data1, '~'));
				}
			}
		if ($mv != '') $msg[$mi] = $mv;
		else $msg[$mi] = BOLTtranslate(BOLTinfoVar($messagePage, $mi));
		if ($data1 != '') $msg[$mi] = str_replace(Array('$1', '$1'), $data1, $msg[$mi]);
		if ($data2 != '') $msg[$mi] = str_replace(Array('$2', '$2'), $data2, $msg[$mi]);
		}
	if (isset($msg['clear'])) {
		if ($msg['clear'] === '') return;
		return "<div class='message'>$msg[clear]</div>";
		}
	return "<div class='message'>" . implode(" ", $msg) . "</div>";
	}

function BOLTmsg($id, $value='', $args='') {
## THIS FUNCTION SETS UP A MESSAGE IN THE MESSAGE ARRAY FOR LATER DISPLAY
	if (isset($args['msg'])) $x = 'msg';
	if (isset($args["msg_$id"])) $x = "msg_$id";
	if ($x != '') {
		if ($args[$x] == '' || $args[$x] == 'false') return;
		$value = $args[$x];
		}
	global $BOLTsession;
	$BOLTsession['MSG'][$id] = BOLTurl2utf($value);
	return; // $BOLTsession['MSG'][$id];
	}

function BOLTpageCheck($check, $page='') {
## CHECKS TO SEE WHETHER $page OR CURRENT PAGE IS IN CHECK (A STRING LIKE site*,main,test.alpha*)
	if ($check == '') return true;
	global $pageLink;
	if ($page == '') $page = $pageLink;
	$c = explode(',', $check);
	foreach ($c as $cc) {
		if ($cc == $page) return true;
		if (substr($cc, -1) == '*' && substr($page, 0, strlen($cc) - 1) == substr($cc, 0, -1)) return true;
		}
	return false;
	}

function BOLTpageshortcuts($link) {
## VARIOUS SHORTCUTS THAT CAN BE USED IN MISC WAYS TO MODIFY LINKS (OR PAGES IN COMMANDS).  USE LEADING .'S LIKE ..PAGE TO PRODUCE P1.P2.PAGE. USE + TIMESTAMP, ^ ID, ~ LOGIN, @ GROUP, ! ACTION, .. -> . (FOR OOPS), SPACE -> _ , & ENDING # IS THREAD
	if (function_exists(myBOLTpageshortcuts)) return myBOLTpageshortcuts($link);
	global $pageLink, $pageArray, $BOLTvar, $BOLTid, $BOLTtime;
	$BOLTloginPages = BOLTconfig('BOLTloginPages', 'login');
	$BOLTgroupPages = BOLTconfig('BOLTgroupPages', 'group');
	if ($link == '') return $pageLink;
	$link = str_replace('&amp;', '&', $link);
	if (strpos($link, "/")) $link = str_replace("/", ".", $link);
	$get = '';
	if (strpos($link, '&') !== false) {
		$get = substr($link, strpos($link, "&"));
		$link = substr($link, 0, strpos($link, "&"));
		}
	if (substr($link, -1) == '#') {
		$thread = true;
		$link = substr($link, 0, -1);
		}
	if (strpos($link, '#') !== false) {
		$anchor = '#' . BOLTutf2url(substr($link, strpos($link, "#") + 1));
		$link = substr($link, 0, strpos($link, "#"));
		}
	$link = str_replace(' ', '_', $link);
	if (BOLTconfig('BOLTutfpages', 'true') == 'true') $link = BOLTutf2url($link);
	else $link = BOLTutf8_strip($link);
	if (substr($link, 0, 1) == '=') $link = $pageLink . '.' . substr($link, 1);
	$link = strtolower(trim($link));
	if (substr($link, 0, 1) == '.') {
		$tempArray = $pageArray;
		$dots = strlen($link) - strlen(ltrim($link, '.'));
		for ($i=0; $i<$dots; $i++) {
			if (isset($tempArray[$i])) $temp .= $tempArray[$i] . '.';
			}
		$link = $temp . substr($link, $dots);
		}
	$rr1 = array('+','^','~','@','!','..',' ','loginlogin');
	$rr2 = array($BOLTtime,$BOLTid,$BOLTloginPages,$BOLTgroupPages,'action','.','_','~~');
	$link = trim(str_replace($rr1, $rr2, $link), '.');
	if ($thread) $link = $link . '.' . BOLTthread("$link.0");
	return $link . $anchor . $get;	
	}

function BOLTprocess($event, $args='') {
## USED TO RUN AN ARRAY OF PRE-, POST-, AND BACKGROUND- PROCESSES
	global $BOLTprocess;
	if (is_array($BOLTprocess[$event])) {
		foreach ($BOLTprocess[$event] as $job) {
			if (function_exists("$job")) $job($args);
			}
		}
	}

function BOLTqueryData($outarray, $data, $args) {
## PART ONE OF DATA QUERY -- SETS UP DATA CHECKS AND RUNS OUTARRAY THROUGH EACH, DELETING ANY PAGES THAT FAIL
	if (empty($outarray)) return Array();
	foreach ($data as $line) {
		$line = strtolower($line);
		$line = str_replace(Array('(&lt;)', '(&gt;)', '(&amp;)'), Array('(<)', '(>)', '(&)'), $line);
		$f = strtolower(substr($line, 0, strpos($line, '(')));
		$v = strtolower(substr($line, strpos($line, '(') + 1));
		if (substr($v, 1, 1) == ')') $query[$f] = $v;
		}
	if (! is_array($query)) $outarray;
	foreach ($query as $f => $v) {
		foreach ($outarray as $page => $line) {
			if (BOLTqueryData2($f, $v, $line)) unset($outarray[$page]);
			}
		}
	if (empty($outarray)) return Array();
	return $outarray;
	}

function BOLTqueryData2($f, $v, $line) {
## PART TWO OF DATA QUERY -- CHECKS ONE SPECIFIC LINE, BASED ON FIELD, VALUE & KEY. RETURNS TRUE IF FAILS, INDICATING PAGE SHOULD BE REMOVED
	$key = substr($v, 0, 1);
	$v = BOLTtrimQuotes(substr($v, 2));
	$line = strtolower($line);
	if(strpos($line, "$f=") === false) return true;
	$data = substr($line, strpos($line, "$f=") + strlen("$f="));
	if (strpos($data, '<>') !== false) $data = substr($data, 0, strpos($data, '<>'));
	switch($key) {
		case '<': 
			return ($data < $v);
		case '>':
			return ($data > $v);
		case '&':
			$range = explode('|', $v); 
			return ($data > $range[0] && $data < $range[1]);
		case ',':
			return (strpos(",$data,", ",$v,") === false);
		case '+':
			return (strpos($data, $v) === false);
		case '-':
			return (strpos($data, $v) !== false);
		case '?':
			return ($data == '');				
		case '!':
			return ($data == $v);
		case '0':
			return (preg_match($v, $data) == 1);
		case '1':
			return (preg_match($v, $data) == 0);
		default:
			return ($data != $v);
		}
	}

function BOLTqueryLink($outarray, $find, $args) {
## SIMPLE CHECK TO SEE WHICH PAGES IN OUTARRAY HAVE THE SPECIFIED LINK IN THEM
	if (empty($outarray)) return Array();
	$find = '<>' . BOLTpageshortcuts($find) . '<>';
	foreach($outarray as $page => $p) {
		$line = explode(':', $p);
		$check = "<>$line[1]<>";
		if (strpos($check, $find) !== false) $out[$page] = $p;
		}
	if (empty($out)) return Array();	
	return $out;
	}

function BOLTqueryText($outarray, $find, $args) {
## FIRST OF THREE FUNCTIONS USED IN QUERY TEXT IN INDEX -- THIS ONE TAKES CARE OF PARENTHESIS
	global $tempSearchArray, $searcharray;
	$tempSearchArray = $outarray;
	if(substr($find, 0, 1) == '(') return; // why this? what about (one && two) || (three && four) 
	            // solution: if no ( in string, do checknext directly, else run through nesting of parens.
	if ($outarray == Array()) return;
	$find = "($find)";
	while (strpos($find, "(") !== false) {
		$find = preg_replace('/\(([^()]*)\)/e', 'BOLTqueryText2("$1", $args)', $find);
		}
	$results = $searcharray[substr($find, 1)];
	if (! is_array($results)) $results = Array();
	foreach($results as $page) $out[$page] = $outarray[$page];
	return $out;
	}

function BOLTqueryText2($find, $args) {
## SECOND OF THREE FUNCTIONS USED IN QUERY TEXT IN INDEX -- THIS ONE TAKES CARE OF && AND ||
	global $searcharray, $searchcount;
	$find = stripslashes(trim($find));
	$find = str_replace(Array('"', "'"), '', $find);  // add a mechanism for finding strings?
	if (strpos($find, '&&') === false && strpos($find, '||') === false) $find = preg_replace('/(\b\s+\b)/', ' && ', $find);
	if (! isset($searchcount)) $searchcount = 0;
	$searchcount = $searchcount + 1;
	if (strpos($find, '&&')) {
		$x = explode('&&', $find); 
		foreach ($x as $i => $ii) {
			$ii = trim($ii);
			if (substr($ii, 0, 1) == "~") $search[$ii] = $searcharray[substr($ii, 1)];
			else $search[$ii] = BOLTqueryText3($ii, $args);
			if ($i == 0) {
				$searchtemp = $search[$ii];
				}
			else {
				if (is_array($search[$ii])) $searchtemp = array_intersect($searchtemp, $search[$ii]);
				else $searchtemp = Array();
				}
			}
		$searcharray[$searchcount] = $searchtemp;
		return "~$searchcount";
		}
	elseif (strpos($find, '||')) {
		$x = explode('||', $find); 
		foreach ($x as $i => $ii) {
			$ii = trim($ii);
			if (substr($ii, 0, 1) == "~") $search[$ii] = $searcharray[substr($ii, 1)];
			else $search[$ii] = BOLTqueryText3($ii, $args);
			if ($i == 0) $searchtemp = $search[$ii];
			else $searchtemp = array_unique(array_merge($searchtemp, $search[$ii]));
			}
		if (! is_array($searchtemp)) $searchtemp = Array();
		$searcharray[$searchcount] = $searchtemp;
		return "~$searchcount";
		}
	else {
		$searcharray[$searchcount] = BOLTqueryText3($find, $args);
		return "~$searchcount";
		}
	}

function BOLTqueryText3($find, $args) {
## THIRD OF THREE FUNCTIONS USED IN QUERY TEXT IN INDEX -- THIS ONE TAKES CARE OF ! AND DOES ACTUAL CHECK
	global $tempSearchArray;
	if ($args['case'] != 'true') $find = strtolower($find);
	if ($args['words'] !== 'false') $s= " ";
	else $s = "<>";
	$tf = true;
	if (substr($find, 0, 1) == "!") {
		$tf = false;
		$find = substr($find, 1);
		}
	if (substr($find, -1) == '*') $find = substr($find, 0, -1);
	else $find = $s . strtolower(trim($find)) . $s;
	foreach($tempSearchArray as $page => $p) {
		$line = explode(':', $p);
		$check = $s . $line[0] . $s;
		if ($args['case'] != 'true') $check = strtolower($check);
		if ($tf === true && strpos($check, $find) !== false) $search[] = $page;
		elseif($tf === false && strpos($check, $find) === false) $search[] = $page;
		}
	return $search;
	}

function BOLTredirect($nextpage) {
## USED TO REDIRECT THE PAGE TO ANOTHER LOCATION
	global $scriptURL, $cleanURL, $BOLTsession, $BOLTfieldKey, $BOLTindexPages;
	$BOLTindexing = BOLTconfig('BOLTindexing', 'active');
	if ($BOLTindexing == 'active' && is_array($BOLTindexPages)) {
		$BOLTindexPages = array_unique($BOLTindexPages);
		$indexArgs['pages'] = implode(',', $BOLTindexPages);
		BOLTindex($indexArgs);
		}
	if (strpos($nextpage, '://') === false) {
		$nextpage = str_replace('&amp;', '&', $nextpage);
		if (isset($cleanURL)) $scriptURL = $cleanURL;
		$nextpage = "$scriptURL$nextpage";
		}
	session_start();
	$_SESSION[$BOLTfieldKey]['MSG'] = $BOLTsession['MSG'];
	$_SESSION[$BOLTfieldKey]['POST'] = $_POST;
	session_write_close();
	header("Location: $nextpage");
	header("Content-type: text/html");
	print_r("<html><head><meta http-equiv=Refresh></head><body></body></html>");
	exit;
	}

function BOLTreplace($in, $out, $type='SAVE') {
## THIS FUNCTION IS CALLED FOR EACH REPLACE DEFINITION TO CREATE $REPLACETABLE. SOME OF THE TYPES OF REPLACES BOLTWIRE UNDERSTANDS ARE: SKIN, HTML, SAVE, OPEN, ANY ZONE. ONLY 2 ROS (REPLACE ON SAVE) SETTINGS IN CORE: ~~ -> MEMBER, AND ~~~ => MEMBER + DATE (SEE SOURCE)
	global $BOLTreplaceTable;
	$BOLTreplaceTable[$type][$in] = $out;
	}

function BOLTsavedata($data, $page='', $auth=true) {
## THIS FUNCTION HANDLES UPDATING OF DATA VALUES. DATA IS AN ARRAY OF FIELD=VALUE PAIRS (USE FIELD='' TO UNSET A DATA FIELD). IF NO PAGE IS SET CURRENT PAGE IS ASSUMED
	global $pageLink, $BOLTid, $target;
	if (! is_array($data)) return;
	if ($page == '') $page = $target;
	else $page = BOLTpageshortcuts($page);
	if (BOLTexists($page)) {
		$content = BOLTloadpage($page, '', 'data', false);
		if (strpos($content, "\n~data~\n") !== false) {
			$getdata = substr($content, strpos($content, "\n~data~\n") + 8);
			$d = explode("\n~\n", $getdata);
			foreach ($d as $line) {
				if (strlen($line) < 3) continue;
				$f = substr($line, 0, strpos($line, ": "));
				$v = substr($line, strpos($line, ": ") + 2);
				$current[$f] = $v;
				}
			}
		}
	foreach ($data as $field => $value) {
		$field = trim($field);
		if ($auth && ! BOLTauth("$page:$field", $BOLTid, 'data')) continue;
		elseif ($value == '') unset($current[$field]);
		else $current[$field] = BOLTsaveEscapes($value, $page);
		}
	if (is_array($current)) {
		foreach ($current as $i => $ii) {
			if ($i == BOLTutf2url($i)) $i = strtolower($i);
			$setdata .= "$i: $ii\n~\n";
			}
		if (substr($setdata, 0, 1) == "\n") $setdata = substr($setdata, 1);
		}
	$setdata = "\n~data~\n" . $setdata;
	BOLTsavepage($page, '', $setdata, false);
	}

function BOLTsaveEscapes($text, $page) {
	global $BOLTreplaceTable;
	$BOLTcodePages = BOLTconfig('BOLTcodePages', 'code');
	$text = str_replace(Array("\r\n", "\r"), "\n", $text);
	if (! BOLTingroup('admin') && ! BOLTingroup('editor')) BOLTreplace('[form', '[fo`rm');
	if (substr($page, 0, strlen($BOLTcodePages) + 1) !== "$BOLTcodePages.") {
//		BOLTreplace('<', '&lt;');
		BOLTreplace('%3c', '<');
		}
//	BOLTreplace('&lt;', '%26lt;');
	BOLTreplace("\n~", "\n&#126;");
	return strtr($text, $BOLTreplaceTable['SAVE']);
	}

function BOLTsavepage($page, $newcontent='', $newdata='', $enableconflict=true, $indexing=true, $saveescapes=true) {
## SYSTEM FUNCTION FOR SAVING PAGES, SECURES AGAINST DISALLOWED CODE
	if (function_exists('myBOLTsavepage')) return myBOLTsavepage($page, $newcontent, $newdata, $enableconflict, $indexing);
	global $pagesDir, $systemPath, $BOLTsession, $BOLTpageStore, $lastedit,  $pageLink, $BOLTindexPages;
	if (strpos($page, '#') !== false) {
		$anchor = '[[' . BOLTurl2utf(substr($page, strpos($page, '#'))) . ']]'; // Note: can't handle [[#anchor|label]]
		$page = BOLTutf2url(substr($page, 0, strpos($page, '#')));
		}
	$page = BOLTfilter(strtolower($page), 'page');
	if ($page == '') BOLTabort('invalid_page_name', "Invalid page name. Please try again.");
	$dir = $pagesDir;
	BOLTfixdir($dir);
	$fpage = BOLTfolders($page);
	if (file_exists("$systemPath/$page") && ! file_exists("$dir/$fpage")) {
		$lastedit = filemtime("$systemPath/$page");
		copy("$systemPath/$page", "$dir/$fpage");
		}
	if (file_exists("$dir/$fpage")) {
		if ($lastedit == '') $lastedit = filemtime("$dir/$fpage");
		$getpage = BOLTloadpage($page, '', 'data');
		if (strpos($getpage, "\n~data~\n") !== false) {
			$data = substr($getpage, strpos($getpage, "\n~data~\n"));
			$oldcontent = substr($getpage, 0, strpos($getpage, "\n~data~\n"));
			}
		else $oldcontent = $getpage;
		}
	if ($newdata != '') $data = $newdata;  // newdata should already be escaped...
	if ($newcontent != '') {
		if ($saveescapes) $newcontent = BOLTsaveEscapes($newcontent, $page);
		if ($anchor != '') {
			if (strpos($oldcontent, $anchor) === false) $content = $oldcontent . "\n$anchor\n" . $newcontent;
			else {
				$before = substr($oldcontent, 0, strpos($oldcontent, $anchor));
				$after = substr($oldcontent, strpos($oldcontent, $anchor) + strlen($anchor));
				if (strpos($after, "[[#") !== false) $after = substr($after, strpos($after, "[[#"));
				else $after = '';
				$content = $before . $anchor . $newcontent . $after;
				}
			}
		else $content = $newcontent;
		if ($content == ' ') $content = '';
		}
	else $content = $oldcontent;
	if ($content != $oldcontent) {
		if (substr($content, -8) == "\n~data~\n") $content = substr($content, 0, -8); // is this necessary?
		if (isset($BOLTsession['CONFLICT'][$page])) {
			if ($BOLTsession['CONFLICT'][$page] >= $lastedit || $page == 'action.edit') unset($BOLTsession['CONFLICT'][$page]);
			elseif ($enableconflict && $newcontent != '') {
				$out = "<box>//" . BOLTtranslate(BOLTinfoVar('site.messages', 'conflict_saving_page', 'Page $1 has been modified. The following changes were overwritten')) . ":// \n\n";
				$out = str_replace('$1', $page, $out);
				$out .= BOLTdiff($oldcontent, $content);
				$out .= "</box>\n";
				$content = $out . $content;
				}
			}
		}
	if ($indexing == true) $BOLTindexPages[] = $page;
	$BOLTpageStore[$page] = $content.$data;
	$mypage = fopen("$dir/$fpage", "wb");
	fwrite($mypage, $content . $data);
	fclose($mypage); 
	clearstatcache();
	}

function BOLTsearchPageList($args, $zone='', $auth=true) {
## SYSTEM FUNCTION USED TO GENERATE STARTING ARRAY OF PAGE NAMES BASED ON PARAMETERS. TAKES: PAGES, PATTERN, GROUP, FOLDER, DIR
	if (isset($args['pages'])) return explode(',', BOLTcsv($args['pages']));
	$pat = NULL;
	if (isset($args['pattern'])) $pat = $args['pattern'];
	elseif (isset($args['group'])) {
		$group = strtolower(BOLTutf2url($args['group']));
		$namespat = '-_a-zA-Z0-9%';
		if (strpos($group, ',') !== false) $patparts = explode(',', $group);
		else $patparts = Array($group);
		foreach ($patparts as $p) {
			if (strpos($p, "*") !== false) {
				if (preg_match("/^[$namespat.*]$/", $p) === false) return Array();
				$p = str_replace('.', '\.', $p);
//				$p = str_replace(',', '|', $p);
				$p = str_replace('*', "[$namespat\.]*", $p);
				$patpart[] = "$p";
				}
			else $patpart[] = str_replace('.', '\.', $p) . "\.[$namespat]+";
			$pat = '/^(' . implode($patpart, '|') . ')$/';
			}
		}
	if (isset($args['folder'])) $folder = $args['folder'];
	else $folder = '';
	if (isset($args['dir'])) $dir = $args['dir'];
	else $dir = ''; //$pagesDir;
	$outarray = BOLTlistpages($pat, $dir, $folder);
	if ($auth && is_array($outarray)) {
		global $BOLTid;
		foreach ($outarray as $i => $ii) {
			if (BOLTauth($ii, $BOLTid, 'view') === false) unset($outarray[$i]);
			}
		}
	$outarray = BOLTsearchPageListPlus($outarray, $args);
	if (! is_array($outarray)) return Array();
	return $outarray;
	}

function BOLTsearchPageListPlus($outarray, $args='') {
	$BOLTvar['$count_matches'] = 0;
	if (isset($args['include'])) {
		$include = strtolower(BOLTutf2url($args['include']));
		if (is_array($outarray)) $outarray = array_merge($outarray, explode(',', $include));
		else $outarray = explode(',', $include);
		}
	if (count($outarray) == 0) return;
	if ($args['exclude'] == '') $args['exclude'] = BOLTconfig('BOLTsearchExclude');
	if ($args['exclude'] != '') {
		$exclude = strtolower(BOLTutf2url($args['exclude']));
		$e = explode(",", $exclude);
		foreach ($e as $ee) {
			if (substr($ee, -1) == '*') {
				$ee = substr($ee, 0, - 1);
				foreach ($outarray as $p => $page) {
					if ($ee == substr($page, 0, strlen($ee))) unset($outarray[$p]);
					}
				}
			elseif (in_array($ee, $outarray)) unset($outarray[array_search($ee, $outarray)]);
			}
		}
	if ($args['type'] == '') $args['type'] = BOLTconfig('BOLTsearchType');
	if ($args['type'] == 'number') {
		foreach ($outarray as $p => $page) {
			$page = substr($page, strrpos($page, '.') + 1);
			$page = str_replace('-', '', $page);
			if (! is_numeric($page)) unset($outarray[$p]);
			}
		}
	elseif ($args['type'] != '') {
		$type = strtolower(BOLTutf2url($args['type']));
		$excludeType = true;
		if (substr($type, 0, 1) == '-') {
			$type = str_replace('-', '', $type);
			$excludeType = false;
			}
		$type = ',' . $type . ',';
		foreach ($outarray as $p => $page) {
			if (strpos($page, '.') !== false) $page = ',' . substr($page, strrpos($page, '.') + 1) . ',';
			else $page = ',' . $page . ',';
			if ($excludeType) {
				if (strpos($type, $page) === false) unset($outarray[$p]);
				}
			elseif (strpos($type, $page) !== false) unset($outarray[$p]);
			}		
		}
	if (strpos(',,true,false,', ','.$args['if'].',') === false && count($outarray) > 0) {
		foreach ($outarray as $i => $p) {
			$cond = BOLTdomarkup($args['if'], $p, '', 'vars');
			if (BOLTMtrue1($cond, 'true', 'if') != 'true') unset($outarray[$i]);
			}
		}
	if (count($outarray) == 0) return;
	$outarray = array_unique($outarray);
	array_unshift($outarray, '');
	unset($outarray[0]);
	$BOLTvar['$count_matches'] = count($outarray);
	if (isset($args['sort'])) return BOLTsort($outarray, $args);
	$sortFunc = 'BOLTsort' . BOLTconfig('BOLTlanguage');
	if ($sortFunc != 'BOLTsort'  && function_exists($sortFunc)) return $sortFunc($outarray);	
	natcasesort($outarray);
	if (isset($args['order'])) return BOLTsort($outarray, $args);
	return $outarray;
	}

function BOLTsecure() {
## THIS FUNCTION IS USED TO VERIFY THAT A FORM WAS SUBMITTED PROPERLY AND SETS THE BOLTARRAY
	global $pageLink, $BOLTarray, $BOLTsession;
	$form = str_replace(".", "-", $pageLink);
	$key = $_POST['boltkey'];
	if ($key == '') BOLTabort('key_missing');
	if ($BOLTsession['KEY'][$pageLink][$key] != "set") BOLTabort('key_invalid');
	$BOLTarray = $BOLTsession['FORM'][$pageLink][$key];
	unset($BOLTsession['FORM'][$pageLink]);
	unset($BOLTsession['KEY'][$pageLink]);
	foreach ($_POST as $field => $value) {
		if (is_array($value)) $value = implode(",", $value);
		$BOLTarray[$field] = $value;
		}
	return $BOLTarray;
	}

function BOLTsnippets($var, $page='') {
## THIS IS THE FUNCTION THAT RETRIEVES DATA TO FILL THE $$MARKUPS IN YOUR SITE OR SKIN. TRIES TO FIND IN THIS ORDER: SYSTEM VAR, DATA VAR, INFO VAR. SPECIAL CASES: PAGE (SITE URL), SKIN, IMG, PUB. THE ORDER OF SEARCHING IS PAGE/SKIN/IMG/PUB, DATA VAR (ON PAGELINK), SYSTEM VAR, (CONFIG VARS COMMENTED OUT), CODE.SNIPPETS.SKIN, CODE.SNIPPETS
	if (function_exists(myBOLTsnippets)) return myBOLTsnippets($var,$page,$skin);
	global $BOLTvar, $BOLTsite, $skinPath, $imgURL, $pubURL, $farmURL, $BOLTskin, $pageLink, $index, $cleanURL, $scriptURL;
	$var = strtolower($var);
	if ($var == 'page') {
		$page = substr($page, 1);
		if (isset($cleanURL)) return $cleanURL . str_replace('.', '/', $page);
		else return "$scriptURL$page";
		}
	if ($var == 'skin' || $var == 'skinpath') {
		if ($BOLTskin != '') return "$skinPath/$BOLTskin";
		else return $imgURL;
		}
	if ($var == 'img') return $imgURL;
	if ($var == 'pub') return $pubURL;
	if ($var == 'farm') return $farmURL;
	if (BOLTvars("$pageLink:$var") != '') return BOLTvars("$pageLink:$var");
	if (BOLTvars("$var") != '') return BOLTvars("$var");
//	if (BOLTconfig("BOLT$var") !== '') return BOLTconfig("BOLT$var");
	$code = BOLTconfig('BOLTcodePages', 'code');
	if ($BOLTskin != '') $out = BOLTinfoVar("$code.snippets.$BOLTskin", $var);
	if ($out == '') $out = BOLTinfoVar("$code.snippets", $var);
	return $out;
	}

function BOLTsort($outarray, $args) {
## SYSTEM FUNCTION WHICH SORTS AN ARRAY BASED ON SORT PARAMETER. SPECIAL HANDLING OF LASTMODIFIED, AND PAGENAMES FOR SPEED. ELSE USES INDEX IF BY A DATA VARIABLE.  ALSO HANDLES THE INCLUDE, EXCLUDE, TYPE, ORDER (REVERSE,RANDOM) PARAMETER, IF, AND COUNT PARAMETERS
	global $pagesDir, $pluginPath, $systemPath, $BOLTvar;
	if ($args['sort'] != '' && $args['sort'] != 'false') {
		if (function_exists("BOLTsort$args[sort]")) {
			$sortFunc = "BOLTsort$args[sort]";
			$outarray = $sortFunc($outarray);
			}
		else {
			if ($args['sort'] == 'lastmodified') {
				foreach ($outarray as $page) $sortarray[$page] = BOLTFlastmodified(Array('page' => $page, 'dir' => $args['dir']));
				}
			elseif (preg_match('/^(p[0-9]{1}|page)$/', $args['sort']) != 0) {
				$index = substr($args['sort'], 1, 1);
				foreach ($outarray as $page) {
					$tempArray = explode(".", $page);
					if ($index == '0') $sortarray[$page] = count($tempArray);
					elseif ($args['sort'] == 'page') $sortarray[$page] = $tempArray[count($tempArray)-1];
					else $sortarray[$page] = $tempArray[$index - 1];
					}
				}
			else {
				if (isset($args['altindex'])) $BOLTindexFile = $args['altindex'] . '.index';
				else $BOLTindexFile = BOLTconfig('BOLTindexFile', 'search.index');
				$searchindex = "\n" . BOLTloadpage($BOLTindexFile, 'indexes');
				foreach ($outarray as $page) {
					if (strpos($searchindex, "\n$page:") === false) $sortarray[$page] = '';
					else {
						$sort = $args['sort'] . '=';
						$line = substr($searchindex, strpos($searchindex, "\n$page: ") + 1);
						if (strpos($line, "\n") !== false) $line = substr($line, 0, strpos($line, "\n"));
						if (strpos($line, $sort) === false) $sortarray[$page] = '';
						else {
							$value = substr($line, strpos($line, $sort) + strlen($sort));
							if (strpos($value, '<>') !== false) $value = substr($value, 0, strpos($value, '<>'));
							$sortarray[$page] = $value;
							}
						}
					}
				}
			if (! is_array($sortarray)) return Array();
			natcasesort($sortarray);
			$outarray = array_keys($sortarray);
			}
		}
	if ($args['order'] == 'reverse' xor $args['sort'] == 'lastmodified') $outarray = array_reverse($outarray, true);
	if ($args['order'] == 'random') { // special code to preserve keys, for infovars
		$shuffle = array(); 
		$keys = array_keys($outarray); 
		shuffle($keys); 
		foreach($keys as $key) $shuffle[$key] = $outarray[$key]; 
		$outarray = $shuffle; 
		}
	array_unshift($outarray, '');
	unset($outarray[0]);
	return $outarray;
	}

function BOLTstopWatch($text) {
## A SPECIAL FUNCTION TO HELP BENCHMARK PROCESSES ON BOLTWIRE SITES. TO USE, SET $BOLTstopWatch=true; IN INDEX.PHP BEFORE CALLING ENGINE 
	global $BOLTstopWatch, $BOLTstopWatchMsg, $BOLTstopWatchTime;
	if (! $BOLTstopWatch) return;
	$now = microtime(true);
	if ($BOLTstopWatchMsg == '') {
		$BOLTstopWatchMsg = "StopWatch:";
		$time = 0;
		}
	else $time = (ceil($now*10000000) - ceil($BOLTstopWatchTime*10000000))/10000000;
//	$time = substr($time, 0, 5);
	$BOLTstopWatchTime = $now;
	$BOLTstopWatchMsg .= "<br />$text: $time seconds ($now)";
	}

function BOLTstripslashes($x) {
## A UTILITY FUNCTION TO STRIP OUT SLASHES ADDED BY PREG_REPLACE
	$blockslashes = BOLTconfig('BOLTblockSlashes');
	$r1 = Array('\"', "\\'"); //, '\{');
	$r2 = Array('"', "'"); //, '{');  
	return str_replace($r1, $r2, $x);
	}

function BOLTstyleAttrs($type, $attr='', $debug=0) {
	$attr = BOLTstripslashes($attr);
	if ($type == 'p' || $type == 'div') {
		$r1 = array(' center', ' left', ' right');
		$r2 = array(' text-align=center', ' text-align=left', ' text-align=right float=right');
		$attr = str_replace($r1, $r2, strtolower($attr));
		}
	$args = BOLTargs($attr);
	$attr = '';
	if ($type == 'a') {
		global $scriptURL;
		if (! isset($args['href'])) $args['href'] = $args[1];
		$args['href'] = BOLTescape($args['href'], false);
		if (strpos($args['href'], "://") === false) $args['href'] = $scriptURL . BOLTpageshortcuts($args['href']);
		}
	foreach((array)$args as $f => $v) {
		if (is_array($v)) continue;
		$v = BOLTtrimQuotes($v);
		if (in_array($f, BOLTattrs($type))) $attr .= " $f='$v' ";
		}
//	if ($attr != '') $attr = str_replace("''", "'", $attr);
	return BOLTescape(str_replace('   ', ' ', " $attr"));
	}

function BOLTthread($g, $dir='') {
## THIS FUNCTION RETURNS THE NEXT AVAILABLE THREAD NUMBER FOR A SUBPAGE
	if (strpos($g, '.')) $g = substr($g, 0, - strlen(strrchr($g, ".")));
	$BOLTthreadStart = BOLTconfig('BOLTthreadStart', 1000);
	$e = $BOLTthreadStart - 1;
	$pages = BOLTlistpages("/^$g\\.\\d/", $dir);
	if (is_array($pages)) {
		foreach($pages as $n) {
			$n = substr($n,strlen($g)+1);
			if (! ereg("^[0-9]+$", $n)) continue;
			$e = max($e,$n);
			}
		}
	$e = $e + 1;
	return $e;
	}

function BOLTtranslate($text, $language='', $reverse=0) {
## THE TRANSLATION ENGINE IN BOLTWIRE FOR SWITCHING KEY PHRASES TO YOUR CHOICE OF LANGUAGE OR BACK
	global $BOLTtranslationArray;
	if ($language == '') $language = BOLTconfig('BOLTlanguage');
	if ($language == '') return $text;
	if (! is_array($BOLTtranslationArray[$language])) {
		if (! BOLTexists("site.language.$language")) return $text;
		$translation = BOLTloadpage("site.language.$language");
		preg_match_all('/^(.+?)(?: :: (.+))/m', $translation, $BOLTtranslationArray[$language]);
		array_unshift($BOLTtranslationArray[$language][1], '');
		array_unshift($BOLTtranslationArray[$language][2], '');
		}
	$index = array_search(trim($text), $BOLTtranslationArray[$language][$reverse + 1]);
	if ($BOLTtranslationArray[$language][2 - $reverse][$index] != '') return $BOLTtranslationArray[$language][2- $reverse][$index];
	return $text;
	}

function BOLTtrimQuotes($text) {
## A UTILITY FUNCTION TO STRIP OUT ' AND " IF AT BEGINNING AND END OF STRING
	if (substr($text, 0, 1) == "'" && substr($text, -1) == "'") $text = substr($text, 1, -1);
	if (substr($text, 0, 1) == '"' && substr($text, -1) == '"') $text = substr($text, 1, -1);
	return $text;
	}

function BOLTtrimLines($text) {
## A UTILITY FUNCTION TO GET RID OF UNWANTED LINE RETURNS FROM CERTAIN BLOCK ELEMENTS
	if (substr($text, 0, 1) == "\n") {
		if (strpos($text, '!') != 1 && strpos($text, '->') !== 1 && strpos($text, '-&gt;') !== 1) $text = substr($text, 1);
		}
	if (substr($text, -1) == "\n") {
		if (substr($text, -2, 1) != '!' && substr($text, -3, 2) != '->' && substr($text, -6, 5) != '&lt;-') $text = substr($text, 0, -1);
		}
	return $text;
	}

function BOLTurl2utf ($x) {
## THIS FUNCTION CONVERTS UTF8 PAGENAMES BACK FROM BOLTWIRE URL. SEE ALSO BOLTutf2url
	if (BOLTconfig('BOLTutfpages', 'true') != 'true') return $x;
	global $BOLTutfEscape;
	if (strpos($x, '%') === false) return $x;
	$x = strtr($x, $BOLTutfEscape);
	$x =  urldecode($x);
	return $x;
	}

function BOLTutf2url ($x) {
## THIS FUNCTION CONVERTS UTF8 PAGENAMES TO AN ACCEPTABLE BOLTWIRE URL. SEE ALSO BOLTurl2utf
	if (BOLTconfig('BOLTutfpages', 'true') != 'true') return $x;
	global $BOLTutfEscape;
	$x = urlencode($x);
	$x = strtr($x, $BOLTutfEscape);
	return $x;
	}

function BOLTutf8_strip($text) {
## STRIPS A UTF STRING TO NORMAL ENGLISH LETTERS (AT LEAST MANY OF THEM). BELOW IS A SAMPLE STRING USED FOR TESTING PURPOSES
	BOLTdefault($utf2asc, Array('%C1' => 'A', '%C2' => 'A', '%C3' => 'A', '%C4' => 'Ae', '%C5' => 'Ao', '%C6' => 'Ae', '%C7' => 'C', '%C8' => 'E', '%C9' => 'E', '%CA' => 'E', '%CB' => 'E', '%CC' => 'I', '%CD' => 'I', '%CE' => 'I', '%CF' => 'I', '%D0' => 'D', '%D1' => 'N', '%DA' => 'U', '%D3' => 'O', '%D4' => 'O', '%D5' => 'O', '%D6' => 'Oe', '%D8' => 'Oe', '%D9' => 'U', '%DB' => 'U', '%DC' => 'Ue', '%DD' => 'Y', '%DE' => 'Th', '%DF' => 'ss', '%E0' => 'a', '%E1' => 'a', '%E2' => 'a', '%E3' => 'a', '%E4' => 'ae', '%E5' => 'ao', '%E6' => 'ae', '%E7' => 'c', '%E8' => 'e', '%E9' => 'e', '%EA' => 'e', '%EB' => 'e', '%EC' => 'i', '%ED' => 'i', '%EE' => 'i', '%EF' => 'i', '%F0' => 'd', '%F1' => 'n', '%F2' => 'o', '%F3' => 'o', '%F4' => 'o', '%F5' => 'o', '%F6' => 'oe', '%F8' => 'oe', '%F9' => 'u', '%FA' => 'u', '%FB' => 'u', '%FC' => 'ue', '%FD' => 'y', '%FE' => 'th', '%FF' => 'y'));
	foreach($utf2asc as $in => $out) $text = str_replace(urldecode($in), $out, $text);
	return $text;
	}

function BOLTvars($var, $auth=true) {
## THIS FUNCTION RETRIEVES A PAGE VARIABLE, CALLING FOR A CACHE IF ONE DOESN'T EXIST
//	if (strpos('(+=', substr($var, 0, 1)) !== false) return '{'.$var.'}';
	global $BOLTvar, $pageLink, $BOLTid, $BOLTzone;
	$var = strtolower(BOLTpageshortcuts($var));
	if (strpos($var, '*:') !== false) {  // vars from stamped pages
		$field = substr($var, strpos($var, '*:') + 1);
		$page = substr($var, 0, strpos($var, ':'));
		if (isset($BOLTvar[$page][$field])) return $BOLTvar[$page][$field];
		BOLTvarCache($field, $page, 'stamps');
		return $BOLTvar[$page][$field];
		}
	if (strpos($var, '::') !== false) {  // Info vars
		$page = substr($var, 0, strpos($var, '::'));
		if ($page == '') $page = $pageLink;
		$field = substr($var, strpos($var, '::') + 2);
		return BOLTinfoVar($page, $field, '', true);
		}
	if (strpos($var, ":") === false) {  // System vars
		if (isset($BOLTvar[strtolower($BOLTzone)]["$$var"])) return $BOLTvar[strtolower($BOLTzone)]["$$var"]; 
		if (isset($BOLTvar["$$var"])) return $BOLTvar["$$var"];
		$page = $pageLink;
		$field = $var;
		}
	else {  // Data Vars
		$page = substr($var, 0, strpos($var, ":"));
		$field = substr($var, strpos($var, ":"));
		if ($auth && ! BOLTauth("$page$field", $BOLTid, 'data')) return;
		if (strpos(" ,:p,:page,:title,:p0,:p1,:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9,:data, ", ",$field,")) $field = substr($field, 1); 
		if ($page == '') $page = $pageLink;
		}
	if (is_array($BOLTvar[$page])) return $BOLTvar[$page][$field]; 
	BOLTvarCache($field, $page, '', $auth);
	return $BOLTvar[$page][$field]; 
	}

function BOLTvarCache($field, $page, $dir='', $auth=true) {
## THIS FUNCTIONS CREATES A FULL SET OF PAGE VARIABLES FOR A GIVEN PAGE AND CACHES THEM	
	global $BOLTvar, $pageLink, $pageArray, $BOLTadmin, $BOLTid, $pagesDir, $systemPath;
	$tempArray = explode(".", $page);
	$BOLTvar[$page]['p0'] = count($tempArray);
	foreach ($tempArray as $i => $ii) {
		$index = "p" . ($i + 1);
		$BOLTvar[$page][$index] = $ii;
		}
	$BOLTvar[$page]['p'] = $page;
	$BOLTvar[$page]['page'] = $tempArray[count($tempArray) - 1];
	if ($dir == 'stamps') {
		$dir = BOLTconfig('BOLTstampsDir', 'stamps');
		$rpage = substr($page, 0, -1);
		}
	else ($rpage = $page);
	if (BOLTexists($rpage, $dir)) {
		$d = BOLTloadpage($rpage, $dir, 'data', $auth);
		if (strpos($d, "\n~data~\n") !== false) {
			$d = substr($d, strpos($d, "\n~data~\n") + 8);
			$d = htmlspecialchars($d, ENT_NOQUOTES);
			$d = str_replace('[form', '[fo>rm', $d);
			$d = explode("\n~\n", $d);
			foreach ($d as $line) {
				if (strpos($line, ": ") === false) continue;
				$f = strtolower(BOLTutf2url(substr($line, 0, strpos($line, ": "))));
				$v = substr($line, strpos($line, ": ") + 2);
//				if (strpos($v, '{?') !== false) $v = preg_replace('/\{\?([.a-zA-Z0-9]+)\}/e', "htmlspecialchars(\$_REQUEST['$1'], ENT_NOQUOTES, 'UTF-8')", $v);
				if (($f == '') || ($v == '')) continue;
				if ($auth && BOLTexists('site.auth.data') && ! BOLTauth("$rpage:$f", $BOLTid, 'data')) continue;
				if ($f == 'diff') {
					$v = 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'), $v);
					$v = BOLTescape($v);
					}
				$v = str_replace('&#126;', '~', $v);
				$v = str_replace('&amp;', '&', $v);
				$BOLTvar[$page][":$f"] = $v;
				$flist[] = $f;
				}
			}
		if (is_array($flist)) $BOLTvar[$page]['data'] = BOLTurl2utf(implode(", ", $flist));
		}
	if (isset($BOLTvar[$page][':title'])) $BOLTvar[$page]['title'] = $BOLTvar[$page][':title'];
	else {
		if (BOLTurl2utf($BOLTvar[$page]['page']) != $BOLTvar[$page]['page']) $BOLTvar[$page]['title'] = BOLTurl2utf($BOLTvar[$page]['page']);
		else $BOLTvar[$page]['title'] = ucwords($BOLTvar[$page]['page']);
		}
	return;
	}

function BOLTvspace($text, $zone='') {
	if ($zone == '' && strpos($text, "\n") === false) return $text;
	$text = preg_replace('/<nolines>(.*)<\/nolines>/Usie', "BOLTescape(BOLTstripslashes('$1'))", $text);
	$text = preg_replace('/<(h[1-6]|blockquote|div|th|td|fieldset|legend)([^>\n]*)>(.*)<\/\1>/Uise', "BOLTvspaceBlock('$3', '$1', '$2')", $text);
	$text = preg_replace('/(<table.+table>)/siUe', "BOLTescape(BOLTstripslashes('$1'))", $text);
	$text = BOLTtrimLines($text);
	if (strpos($text, "\n\n") === false) $nowrap = true;
	$paragraphs = explode("\n\n", $text);
	foreach ($paragraphs as $p => $pp) {
		if (strpos($pp, "\n") !== false) {
			$lines = explode("\n", $pp);
			foreach($lines as $l => $ll) {
				if(BOLTvspaceCheck($ll)) $lines[$l] = $ll . '<br />';
				else $lines[$l] = "$ll\n";
				}
			$pp = implode('', $lines);
			if (substr($pp, -6) == '<br />') $pp = substr($pp, 0, -6);				
			}
		if (BOLTvspaceCheck($pp)) $paragraphs[$p] = "<p>$pp</p>";		
		if (preg_match('/^~~([0-9]+)~~$/', $pp)) $paragraphs[$p] = "$pp<p />";
		}
	$text = implode("\n\n", $paragraphs);
	if ($nowrap) {
		if (substr($text, 0, 3) == '<p>' && substr($text, -4) == '</p>') $text = substr($text, 3, -4);
		}
	$text = str_replace('<p></p>', '', $text);
	return $text;
	}

function BOLTvspaceBlock($text, $type, $attr) {
	$text = BOLTstripslashes(BOLTtrimLines($text));
	if (strpos($attr, "class='code'") == false) $text = BOLTvspace($text);
	if (substr($type, 0, 1) == 'h' || $type == 'legend') $end = "\n";
	return BOLTescape("<$type$attr>$text</$type>") . $end;
	}

function BOLTvspaceCheck($text, $zone='') {
## FUNCTION USED TO TELL WHETHER A LINE OF TEXT SHOULD BE GIVEN PARAGRAPH OR LINEBREAK MARKS, OR LEFT ALONE
	if (strpos($text, "\n") !== false) return;
	$text = str_replace(Array('&lt;', '&gt;'), Array('<', '>'), $text);
	if (preg_match('/^<br \/>(\n<br \/>){0,}$/', $text) == 1) return;
	if (strpos(',</div>,<hr />,</p>,<br />,</blockquote>,', ",$text,") !== false) return;
	if (preg_match('/^<(p|div|blockquote|ul|ol|h[1-6])([^>\n]*)>((.*)<\/\1>)?$/s', $text) == 1) return;
	if (preg_match('/^(<\/?(table|tr|th|td)([^>]*)>)+$/', $text) == 1) return; 
	if (preg_match('/^\[(fo>?rm|session)[^\]]*\]$/', $text) == 1) return;
	if (preg_match('/^(~~([0-9]+)~~\n?)+$/', $text) == 1) return;
	if ($text == '[results]' || $text == '[messages]' || $text == '<hr />') return;
	return true;
	}
Return current item: BoltWire