-- Table structure for table `txp_page`
--

CREATE TABLE `txp_page` (
  `name` varchar(128) NOT NULL DEFAULT '',
  `user_html` text NOT NULL,
  PRIMARY KEY (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=1;

--
-- Dumping data for table `txp_page`
--

INSERT INTO `txp_page` VALUES ('sampology','<txp:output_form form=\"Meta\" />\r\n	<txp:output_form form=\"Head+Nav\" />\r\n	<div id=\"contentWrap\">\r\n		<div id=\"content\">\r\n			<txp:if_section name=\"default\">\r\n				<div id=\"top-bar\">\r\n					<txp:output_form form=\"ContentHead\" />\r\n					<txp:output_form form=\"newsletter\" />\r\n				</div>  \r\n				<txp:output_form form=\"ContentSubHead\" />\r\n			</txp:if_section>\r\n			<div id=\"contentPageCol1\">\r\n				<h2><txp:section title=\"1\" /></h2>	\r\n				<txp:if_search>\r\n			   		<txp:output_form form=\"Search\" />\r\n				</txp:if_search>\r\n				<txp:if_individual_article>\r\n					<txp:if_section name=\"blog\">\r\n						<txp:article>\r\n							<h3><txp:title /></h3>\r\n							<p class=\"posted\">Posted on <txp:posted /></p>\r\n							<txp:body />\r\n							<iframe src=\"http://www.facebook.com/plugins/like.php?href=<txp:permlink />&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light\" scrolling=\"no\" frameborder=\"0\" allowTransparency=\"true\" style=\"border:none; overflow:hidden; width:450px; height:30px\"></iframe>\r\n						</txp:article>\r\n					<txp:else />\r\n						<txp:article />\r\n					</txp:if_section>\r\n				<txp:else />\r\n					<txp:if_section name=\"audio\">\r\n						<txp:article_custom status=\"sticky\" section=\"audio\">\r\n							<txp:body />\r\n						</txp:article_custom>\r\n					<txp:else />\r\n						<txp:if_section name=\"video\">\r\n							<txp:article_custom status=\"sticky\" section=\"video\">\r\n								<txp:body />\r\n							</txp:article_custom>\r\n						<txp:else />\r\n							<txp:article limit=\"8\" status=\"live\" form=\"short-entry\" />\r\n							<ul id=\"rssThumbNav\">\r\n								<li class=\"left\"><txp:older>Older articles</txp:older></li>\r\n								<li class=\"right\"><txp:newer>Newer articles</txp:newer></li>\r\n							</ul>\r\n						</txp:if_section>\r\n					</txp:if_section>\r\n				</txp:if_individual_article>\r\n				<txp:if_section name=\"gallery\">\r\n					<txp:output_form form=\"Gallery\" />\r\n				</txp:if_section>\r\n				<txp:if_section name=\"dates\">\r\n					<txp:mka_ical wraptag=\"ul\" break=\"li\" url=\"http://ws.audioscrobbler.com/1.0/artist/Sampology/events.ics\" pastevents=\"0\">\r\n					  	<h3>{title}</h3>\r\n						<p class=\"date\">{date}</p>\r\n					  	<p>{description}</p>\r\n					</txp:mka_ical>\r\n				</txp:if_section>\r\n			</div>\r\n			<div id=\"contentPageCol2\">\r\n				<txp:output_form form=\"Social\" />\r\n				<txp:if_section name=\"blog,video,audio,default\">\r\n					<txp:output_form form=\"Twitter\" />\r\n				</txp:if_section>\r\n			</div>				\r\n		</div>\r\n	</div>\r\n<txp:output_form form=\"Footer\" />'),('singleCol','<txp:output_form form=\"Meta\" />\r\n\r\n<body>\r\n	<div id=\"container\">\r\n		<txp:output_form form=\"Head+Nav\" />\r\n\r\n		<div id=\"contentWrap\">\r\n			<div id=\"content\">	\r\n\r\n<txp:if_search>\r\n   <txp:output_form form=\"Search\" />\r\n</txp:if_search>\r\n\r\n				<txp:if_section name=\"gallery\">\r\n				 <txp:output_form form=\"Gallery\" />\r\n				</txp:if_section>\r\n\r\n			</div>\r\n		</div>\r\n\r\n		<txp:output_form form=\"Footer\" />'),('error_default','<txp:output_form form=\"Meta\" />\r\n<!-- HTML Header Section End -->\r\n<body>\r\n	<div id=\"container\">\r\n<!-- Nav Section  -->\r\n\r\n		<txp:output_form form=\"Head+Nav\" />\r\n\r\n<!--  Nav Section End -->\r\n		<div id=\"contentWrap\">\r\n				<div id=\"content\">	\r\n<div id=\"errorPage\">\r\n		\r\n <h1 class=\"error-status\">Oops nothing here</h1>\r\n		<p class=\"error-msg\">Whatever you are looking for is not here, try using the navigation at the top of the page. Cheers</p>\r\n</div>\r\n</div>\r\n	</div>\r\n<!-- Footer Content Section  -->\r\n<txp:output_form form=\"Footer\" />'),('static','<txp:output_form form=\"Meta\" />\r\n	<txp:output_form form=\"Head+Nav\" />\r\n	<div id=\"contentWrap\">\r\n		<div id=\"content\">\r\n			<div id=\"contentPageCol1\">\r\n				<txp:if_section name=\"about,dates\">\r\n					<txp:article status=\"sticky\" />\r\n					<txp:article limit=\"1\" />\r\n				</txp:if_section>\r\n				<txp:if_section name=\"contact\">\r\n					<txp:article_custom id=\"9\" form=\"no-title\" />\r\n					<txp:output_form form=\"Contact\" />\r\n				</txp:if_section>\r\n			</div>\r\n			<div id=\"contentPageCol2\">\r\n				<txp:output_form form=\"Social\" />\r\n			</div>					\r\n		</div>\r\n	</div>\r\n<txp:output_form form=\"Footer\" />'),('default','<txp:output_form form=\"header\" />\r\n<txp:soo_if_frontpage>\r\n<txp:output_form form=\"home\" />\r\n<txp:else />\r\n<txp:output_form form=\'<txp:section />\' />\r\n</txp:soo_if_frontpage>\r\n<txp:output_form form=\"footer\" />');

--
-- Table structure for table `txp_plugin`
--

CREATE TABLE `txp_plugin` (
  `name` varchar(64) NOT NULL DEFAULT '',
  `status` int(2) NOT NULL DEFAULT '1',
  `author` varchar(128) NOT NULL DEFAULT '',
  `author_uri` varchar(128) NOT NULL DEFAULT '',
  `version` varchar(10) NOT NULL DEFAULT '1.0',
  `description` text NOT NULL,
  `help` text NOT NULL,
  `code` mediumtext NOT NULL,
  `code_restore` mediumtext NOT NULL,
  `code_md5` varchar(32) NOT NULL DEFAULT '',
  `type` int(2) NOT NULL DEFAULT '0',
  `load_order` tinyint(3) unsigned NOT NULL DEFAULT '5',
  `flags` smallint(5) unsigned NOT NULL DEFAULT '0',
  UNIQUE KEY `name` (`name`),
  KEY `status_type_idx` (`status`,`type`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

--
-- Dumping data for table `txp_plugin`
--

INSERT INTO `txp_plugin` VALUES ('lam_image_uploader',0,'Steve Lam','http://www.stevelam.ca','0.6c','Upload Images from the Write tab (based on stm_image_uploader)','<h3>lam_image_uploader v0.6c</h3>\r\n\r\n<p>Allows you to upload images via the Write tab. Based on <a href=\"http://laborblog.3st.de/image-uploader-fuer-textpattern\">stm_image_uploader</a> but with a few improvements including:</p>\r\n\r\n<ul>\r\n<li>automatically appending image id to article</li>\r\n<li>or: show a text link to manually attach id to article</li>\r\n<li>or: show a text link to manually append multiple id\'s to article</li>\r\n<li>ability to display thumbnail</li>\r\n<li>assign image category on upload</li>\r\n<li>assign caption on upload</li>\r\n<li>move the upload form to the left sidebar instead of below the excerpt</li>\r\n<li>installable/removable preferences for all of the above</li>\r\n</ul>\r\n\r\n<h3>Installation</h3>\r\n\r\n<p>Once plugin is installed, head over to admin -> extensions and install the preferences. They will be stored in your database. You can also remove the preferences at any time by returning to the same page.</p>\r\n\r\n\r\n','// 0.6c\r\nif (@txpinterface == \'admin\') {	\r\n	add_privs(\'lam_image_uploader_prefs\', \'1,2\');\r\n  	add_privs(\'handle_picture_upload_form\',\'1,2,3,4,5\');\r\n	add_privs(\'picture_upload_form\',\'1,2,3,4,5\');\r\n	register_callback(\"handle_picture_upload_form\", \"picture_upload_form\");\r\n  	register_callback(\"setup_picture_upload\", \"article\");\r\n	register_tab(\'extensions\', \'lam_image_uploader_prefs\', \'Image Uploader\');\r\n	register_callback(\'lam_image_uploader_prefs\', \'lam_image_uploader_prefs\');\r\n}\r\n\r\nfunction setup_picture_upload($event, $step) {\r\n	global $prefs;\r\n\r\n	echo \'<script type=\"text/javascript\">\r\n	var parentElement = document.getElementById(\"\';\r\n	if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n		echo \'article-col-1\");\';\r\n	} else { echo \'article-main\");\r\n		var p = document.createElement(\"p\");\r\n		var label = document.createElement(\"label\");\r\n		label.innerHTML = \"\'.gTxt(\'upload_image\').\'\";\r\n		label.setAttribute(\"id\",\"pictures-upload\");\r\n		label.setAttribute(\"name\",\"pictures-upload\");\r\n		p.appendChild(label);\r\n		parentElement.appendChild(p);\';\r\n	}\r\n	echo \'var iframe = document.createElement(\"iframe\");\r\n	iframe.setAttribute(\"id\", \"lam-pictures\");\r\n	iframe.setAttribute(\"name\",\"lam-pictures\");\r\n	iframe.setAttribute(\"border\",\"0\");\r\n	iframe.setAttribute(\"frameBorder\",\"0\");\r\n	iframe.setAttribute(\"src\", \"index.php?event=picture_upload_form\");\';\r\n	echo \'\r\n	iframe.style.width = \"100%\";\r\n	iframe.setAttribute(\"height\",\"235px\");\r\n	iframe.style.border = \"none\";\';\r\n	\r\n	if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n		echo \'parentElement.appendChild(iframe);\';\r\n	} else { echo \'p.appendChild(iframe);\';}\r\n	echo \'\r\n		function adjustIFrameSize(iframeWindow) {\r\n		if (iframeWindow.document.height) {\r\n			var iframeElement = document.getElementById (\"lam-pictures\");\r\n			iframeElement.style.height = iframeWindow.document.height + 25 + \"px\";\r\n			iframeElement.style.width = iframeWindow.document.width + \"px\";\r\n		} else if (document.all) {\r\n			var iframeElement = document.all[\"lam-pictures\"];\r\n			if (iframeWindow.document.compatMode &&\r\n			iframeWindow.document.compatMode != \"BackCompat\") {\r\n			iframeElement.style.height =\r\n			iframeWindow.document.documentElement.scrollHeight + 5 + \"px\";\r\n			iframeElement.style.width =\r\n			iframeWindow.document.documentElement.scrollWidth + 5 + \"px\";\r\n			} else {\r\n				iframeElement.style.height =\r\n				iframeWindow.document.body.scrollHeight + 5 + \"px\";\r\n				iframeElement.style.width = iframeWindow.document.body.scrollWidth\r\n				+ 5 + \"px\";\r\n			}\r\n		}\r\n	}\r\n	</script>\';\r\n}\r\n/// Inline Picture Upload\r\n// -------------------------------------------------------------\r\nfunction handle_picture_upload_form($attr) {\r\n	ob_start();\r\n	ob_end_clean();\r\n	global $prefs;\r\necho \'<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\r\n	\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\r\n<html>\r\n	<head>\r\n		<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\">\r\n		<title>Picture Upload</title>\r\n		<link rel=\"stylesheet\" href=\"textpattern.css\" type=\"text/css\" media=\"screen\" title=\"no title\" charset=\"utf-8\">\r\n		<script type=\"text/javascript\" src=\"jquery.js\"></script>\r\n		<style type=\"text/css\" media=\"screen\">\r\n		body {\r\n			background:none !important;\r\n			background-color:inherit;\r\n		}\r\n      		form.upload-form {\r\n      			text-align:left;\r\n      			overflow:hidden;\r\n      			width:100%;\r\n      		}\r\n      		input.file {\r\n      			margin-top:0;\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n      			echo \'width:140px;\';\r\n      		}\r\n      		echo \'\r\n      		}\r\n      		input.alt {\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n      			echo \'width:140px;\';\r\n      		} else {\r\n      			echo \'width:400px;\';\r\n      			}\r\n      		echo \'}\r\n      		#image-category {\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n			echo \'max-width:160px;\';\r\n		} else {\r\n			}\r\n		echo \'}\r\n      		label {\r\n      			clear:both;\r\n        		display:block;\r\n                        margin-top:10px;\r\n      		}\r\n      		input.smallerbox {\r\n      			display:block;\r\n      			clear:both;\r\n      			margin-top:10px;\r\n      		}\r\n      		textarea {\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n      				echo \'width:140px;\';\r\n      			} else {\r\n      				echo \'width:400px;\';\r\n      			}\r\n      		echo \'\r\n      			height:80px;\r\n      		}\r\n      		.error {\r\n      			color:#fff;\r\n      			padding:5px 0;\r\n      			font-size:11px;\r\n      			background:#900;\r\n      			width:99%;\r\n      			clear:both;\r\n      		}\r\n      		input.result {\r\n      			border: 2px solid #11aa1b;\r\n      			margin: 20px 0;\r\n      			width: 146px;\r\n      		}\r\n      		#lam-attach, #lam-append {\r\n      			margin:20px 0;\r\n      		}\r\n		</style>\r\n		\r\n		<script type=\"text/javascript\">\r\n		function insertid(id, type) {\r\n			var MyElement = parent.document.getElementById(\"article-image\");\r\n			if (type == \"attach\") {\r\n				MyElement.value = id;\r\n			}\r\n			if (type == \"append\") {\r\n				if(MyElement.value == \"\") {\r\n					MyElement.value = id;\r\n				} else {\r\n					MyElement.value += \",\"+id;\r\n				}\r\n			}\r\n			return true;\r\n		}\r\n		$(document).ready(function() {\r\n			$(\"#lam_show_hide\").click(function () {\r\n				$(\"#lam_image_uploader\").toggle();\r\n   			 });\r\n 		 });\r\n		</script>\r\n	</head><body style=\"border:0;\" onload=\"parent.adjustIFrameSize(window);\">\';\r\n	if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n		echo \'<h3 class=\"plain\" style=\"text-align:left\"><a href=\"javascript:void(0);\" id=\"lam_show_hide\" onload>\'.gTxt(\'upload_image\').\'</a></h3><div id=\"lam_image_uploader\">\';\r\n	}\r\n	global $file_max_upload_size;\r\n	if (!$file_max_upload_size || intval($file_max_upload_size)==0) $file_max_upload_size = 2*(1024*1024);\r\n	$max_file_size = (intval($file_max_upload_size) == 0) ? \'\': intval($file_max_upload_size);\r\n	\r\n	if(isset($_FILES[\'thefile\'])) {\r\n		global $txpcfg, $extensions, $txp_user, $img_dir, $ext;\r\n		extract($txpcfg);\r\n		$meta = doSlash(gpsa(array(\'caption\', \'alt\', \'category\')));\r\n		$img_result = image_data2($_FILES[\'thefile\'], $meta);\r\n		\r\n		if(is_array($img_result) && isset($img_result[1])) {\r\n			if($prefs[\'lam_image_uploader_auto_append\'] ==\'1\') {\r\n				echo \'<script type=\"text/javascript\">\';\r\n				echo \"insertid($img_result[1], \'attach\');</script>\";\r\n			}\r\n			if($prefs[\'lam_image_uploader_show_thumbnail\'] == \'1\') {\r\n				echo \'<img src=\"\'.hu.$img_dir.\'/\'.$img_result[1].\'t\'.$ext;\r\n				if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n				echo \'\" width=\"150\" />\';\r\n				} else {\r\n					echo \'\" style=\"max-width:400px\" />\';\r\n				}\r\n			}\r\n			if($prefs[\'lam_image_uploader_show_image_id\'] == \'1\') {\r\n				echo \"<div><input type=\\\"text\\\" onfocus=\\\"this.select()\\\" name=\\\"show_image_id\\\" class=\\\"edit result\\\" value=\'<txp:image id=\\\"$img_result[1]\\\" />\' /></div>\";\r\n			}		\r\n			if($prefs[\'lam_image_uploader_show_attach_image\'] == \'1\') {\r\n				echo \"<div id=\\\"lam-attach\\\"><a href=\\\"javascript:void(0);\\\" onclick=\\\"insertid(\'$img_result[1]\',\'attach\');\\\">\".lam_image_uploader_gTxt(\'attach_image\').\"</a></div>\";\r\n			}\r\n			if($prefs[\'lam_image_uploader_show_append_image\'] == \'1\') {\r\n				echo \"<div id=\\\"lam-append\\\"><a href=\\\"javascript:void(0);\\\" onclick=\\\"insertid(\'$img_result[1]\',\'append\');\\\">\".lam_image_uploader_gTxt(\'append_image\').\"</a></div>\";\r\n			}\r\n		} else {\r\n			echo \'<div class=\"error\"><p>\'.$img_result.\'</p></div>\';\r\n		}\r\n	}\r\n	echo upload_form_for_page(\'picture\',\'file_insert\',\'picture_upload_form\', \'\',$max_file_size);\r\necho\'</div></body></html>\';\r\n	exit;\r\n}\r\n// -------------------------------------------------------------\r\nfunction image_data2($file , $meta = \'\', $id = \'\', $uploaded = true) {\r\n	global $txpcfg, $extensions, $txp_user, $prefs, $file_max_upload_size;\r\n	extract($txpcfg);\r\n\r\n	$name = $file[\'name\'];\r\n	$error = $file[\'error\'];\r\n	$file = $file[\'tmp_name\'];\r\n	if ($uploaded) {\r\n		$file = get_uploaded_file($file);\r\n		if ($file_max_upload_size < filesize($file)){\r\n			unlink($file);\r\n			return upload_get_errormsg(UPLOAD_ERR_FORM_SIZE);\r\n		}\r\n	}\r\n	list($w, $h, $extension) = getimagesize($file);\r\n	global $extensions;\r\n	$extensions = array(0,\'.gif\',\'.jpg\',\'.png\',\'.swf\');\r\n	define(\"IMPATH\",$prefs[\'path_to_site\'].\'/\'.$prefs[\'img_dir\'].\'/\');\r\n	include txpath.\'/lib/class.thumb.php\';\r\n	\r\n	if (($file !== false) && @$extensions[$extension]) {\r\n		global $ext;\r\n		$ext = $extensions[$extension];\r\n		$name = doSlash(substr($name, 0, strrpos($name, \'.\')).$ext);\r\n		if ($meta == false){\r\n			$meta = array(\'category\' => \'\',\'caption\' => \'\',\'alt\' => \'\');\r\n		}\r\n\r\n		extract($meta);\r\n		$q =\"name = \'$name\', ext = \'$ext\', w = $w, h = $h, alt = \'$alt\', caption = \'$caption\', category = \'$category\', date = now(), author = \'$txp_user\'\";\r\n\r\n		if (empty($id)) {\r\n			$rs = safe_insert(\'txp_image\',$q);\r\n			$id = $GLOBALS[\'ID\'] = mysql_insert_id();\r\n		} else {\r\n			$id = assert_int($id);\r\n			$rs = safe_update(\'txp_image\',$q,\"id = $id\");\r\n		}\r\n\r\n		if(!$rs) {\r\n			return gTxt(\'image_save_error\');\r\n		} else {\r\n			$newpath = IMPATH.$id.$ext;\r\n\r\n			if (shift_uploaded_file($file, $newpath) == false) {\r\n				$id = assert_int($id);\r\n				safe_delete(\'txp_image\',\"id = $id\");\r\n				safe_alter(\'txp_image\',\"auto_increment = $id\");\r\n\r\n				if (isset($GLOBALS[\'ID\'])) {\r\n					unset( $GLOBALS[\'ID\']);\r\n				}\r\n				return $newpath.sp.gTxt(\'upload_dir_perms\');\r\n			} else {\r\n				@chmod($newpath, 0644);\r\n\r\n				// Auto-generate a thumbnail using the last settings\r\n				if (isset($prefs[\'thumb_w\'], $prefs[\'thumb_h\'], $prefs[\'thumb_crop\'])) {\r\n					$t = new txp_thumb( $id );\r\n					$t->crop = ($prefs[\'thumb_crop\'] == \'1\');\r\n					$t->hint = \'0\';\r\n					if (is_numeric($prefs[\'thumb_w\'])) $t->width = $prefs[\'thumb_w\'];\r\n					if (is_numeric($prefs[\'thumb_h\'])) $t->height = $prefs[\'thumb_h\'];\r\n					$t->write();\r\n				}\r\n				$message = gTxt(\'image_uploaded\', array(\'{name}\' => $name));\r\n				return array($message, $id);\r\n			}\r\n		}\r\n	} else {\r\n		if ($file === false) {\r\n			return upload_get_errormsg($error);\r\n		} else {\r\n			return gTxt(\'only_graphic_files_allowed\');\r\n		}\r\n	}\r\n}\r\n// -------------------------------------------------------------\r\nfunction upload_form_for_page($pophelp, $step, $event, $id = \'\', $max_file_size = \'1000000\', $label_id = \'\', $class = \'upload-form\') {\r\n	global $sort, $dir, $page, $search_method, $crit, $prefs;\r\n	$class = ($class) ? \' class=\"\'.$class.\'\"\' : \'\';\r\n	$categories = getTree(\"root\",\"image\");\r\n	$label_id = ($label_id) ? $label_id : $event.\'-upload\';\r\n	$lam_image_file = ($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') ? fInput(\'file\',\'thefile\',\'\',\'file edit\',\'\',\'\',\'11\') : fInput(\'file\',\'thefile\',\'\',\'file edit\',\'\',\'\',\'15\');\r\n	$lam_image_alt = ($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') ? fInput(\'text\', \'alt\', \'\', \'alt edit\',\'\',\'\',\'22\') : fInput(\'text\', \'alt\', \'\', \'alt edit\');\r\n	$lam_image_caption = ($prefs[\'lam_image_uploader_image_caption\'] == \'1\') ? \'<label for=\"caption\">\'.gTxt(\'caption\').\'</label>\'.\r\n	\'<textarea id=\"caption\" name=\"caption\" cols=\"18\" rows=\"5\"></textarea>\' : \'\';\r\n	$lam_image_categories = ($prefs[\'lam_image_uploader_image_categories\'] == \'1\') ? \'<label for=\"category\">\'.gTxt(\'image_category\').\'</label>\'.treeSelectInput(\'category\', $categories, \'\', \'image-category\') : \'\';\r\n	\r\n	return n.n.\'<form\'.$class.\' method=\"post\" enctype=\"multipart/form-data\" action=\"index.php\">\'.\r\n	n.\'<div>\'.\r\n	(!empty($max_file_size)? n.hInput(\'MAX_FILE_SIZE\', $max_file_size): \'\').\r\n	n.eInput($event).n.sInput($step).n.hInput(\'id\', $id).n.hInput(\'sort\', $sort).n.hInput(\'dir\', $dir).n.hInput(\'page\', $page).\r\n	n.hInput(\'crit\', $crit).\r\n	$lam_image_file.$lam_image_categories.\'<label for=\"alt\">\'.gTxt(\'alt_text\').\'</label>\'.\r\n	$lam_image_alt.$lam_image_caption.\r\n	fInput(\'submit\', \'\', gTxt(\'upload\'), \'smallerbox\').\r\n	n.\'</div>\'.\r\n	n.\'</form>\';\r\n}\r\n// -------------------------------------------------------------\r\nfunction lam_image_uploader_prefs($event, $step) {\r\n	global $prefs;\r\n	switch ($step) {\r\n	case \'remove\':\r\n		$lam_status = lam_image_uploader_gTxt(\'preferences_removed\');\r\n		break;\r\n	case \'install\':\r\n		$lam_status = lam_image_uploader_gTxt(\'preferences_installed\');\r\n		break;\r\n	case \'update\':\r\n		$lam_status = gTxt(\'preferences_saved\');\r\n		break;\r\n	default:\r\n		$lam_status = \'\';\r\n	}\r\n	\r\n      	pagetop(lam_image_uploader_gTxt(\'prefs\'), $lam_status);\r\n	$checkInstalled = fetch(\'event\',\'txp_prefs\',\'name\',\'lam_image_uploader_show_thumbnail\');\r\n	\r\n      	if ($step == \'update\') {\r\n      		extract(doSlash(psas(array(\r\n      			\'show_thumbnail\', \'show_image_id\', \'image_caption\', \'show_attach_image\', \'show_append_image\', \'auto_append\', \'image_categories\', \'move_sidebar\'\r\n      		))));\r\n      		$show_thumbnail  = ($show_thumbnail == \'1\') ? $show_thumbnail : \'0\';\r\n      		$show_image_id = ($show_image_id == \'1\') ? $show_image_id : \'0\';\r\n      		$image_caption = ($image_caption == \'1\') ? $image_caption : \'0\';\r\n      		$show_attach_image  = ($show_attach_image == \'1\') ? $show_attach_image : \'0\';\r\n      		$show_append_image = ($show_append_image == \'1\') ? $show_append_image : \'0\';\r\n      		$auto_append  = ($auto_append == \'1\') ? $auto_append : \'0\';\r\n      		$image_categories = ($image_categories == \'1\') ? $image_categories : \'0\';\r\n      		$move_sidebar = ($move_sidebar == \'1\') ? $move_sidebar : \'0\';\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_thumbnail\'\", \"name = \'lam_image_uploader_show_thumbnail\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_image_id\'\", \"name = \'lam_image_uploader_show_image_id\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$image_caption\'\", \"name = \'lam_image_uploader_image_caption\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_attach_image\'\", \"name = \'lam_image_uploader_show_attach_image\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_append_image\'\", \"name = \'lam_image_uploader_show_append_image\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$auto_append\'\", \"name = \'lam_image_uploader_auto_append\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$image_categories\'\", \"name = \'lam_image_uploader_image_categories\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$move_sidebar\'\", \"name = \'lam_image_uploader_move_sidebar\'\");\r\n      		$prefs = get_prefs();\r\n      	}\r\n      	if($step == \'remove\') {\r\n      		lam_image_uploader_install(\'remove\');\r\n      		$checkInstalled = fetch(\'event\',\'txp_prefs\',\'name\',\'lam_image_uploader_show_thumbnail\');\r\n      	} else if($step == \'install\') {\r\n      		lam_image_uploader_install(\'install\');\r\n      		$checkInstalled = fetch(\'event\',\'txp_prefs\',\'name\',\'lam_image_uploader_show_thumbnail\');\r\n      	}\r\n	if($checkInstalled) {\r\n      	echo n.n.\'<div style=\"margin: 3em auto auto auto; width: 30em;\">\'.\r\n      	n.n.hed(lam_image_uploader_gTxt(\'prefs\'), \'1\').\r\n      	n.n.form(\r\n      		n.eInput(\'lam_image_uploader_prefs\').\r\n      		n.sInput(\'update\').\r\n      		n.n.tag(\r\n      			n.n.tag(gTxt(\'edit_preferences\'), \'legend\').\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_thumbnail\').br.\r\n      				n.yesnoRadio(\'show_thumbnail\', $prefs[\'lam_image_uploader_show_thumbnail\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_image_id\').br.\r\n      				n.yesnoRadio(\'show_image_id\', $prefs[\'lam_image_uploader_show_image_id\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'image_caption\').br.\r\n      				n.yesnoRadio(\'image_caption\', $prefs[\'lam_image_uploader_image_caption\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_attach_image\').br.\r\n      				n.yesnoRadio(\'show_attach_image\', $prefs[\'lam_image_uploader_show_attach_image\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_append_image\').br.\r\n      				n.yesnoRadio(\'show_append_image\', $prefs[\'lam_image_uploader_show_append_image\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'auto_append\').br.\r\n      				n.yesnoRadio(\'auto_append\', $prefs[\'lam_image_uploader_auto_append\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'image_categories\').br.\r\n      				n.yesnoRadio(\'image_categories\', $prefs[\'lam_image_uploader_image_categories\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'move_sidebar\').br.\r\n      				n.yesnoRadio(\'move_sidebar\', $prefs[\'lam_image_uploader_move_sidebar\'])\r\n      			)\r\n      		, \'fieldset\').\r\n      		n.n.fInput(\'submit\', \'update\', \'Update\', \'smallerbox\')\r\n	).n.n.\'</div>\';\r\n	}\r\n	echo n.n.\'<div style=\"margin: 3em auto auto auto; width: 30em;\">\'.\r\n      	n.n.hed(lam_image_uploader_gTxt(\'install\'), \'1\');\r\n      	echo \'<form method=\"post\" action=\"index.php\">\';\r\n      	echo hInput(\'event\',\'lam_image_uploader_prefs\');\r\n      	if(empty($checkInstalled)) {  \r\n      		echo fInput(\'submit\', \'step\', \'install\', \'smallerbox\');\r\n      	} else {\r\n      		echo fInput(\'submit\', \'step\', \'remove\', \'smallerbox\');\r\n      		}\r\n      	echo \'</form>\';\r\n}\r\n// -------------------------------------------------------------\r\nfunction lam_image_uploader_install($install) {\r\n      	global $prefs;\r\n      	$updated = false;\r\n      	$settings = \"prefs_id = 1, type = 2, event = \'admin\', position = 0\";\r\n	if($install == \'install\') {\r\n        	if (!isset($prefs[\'lam_image_uploader_show_thumbnail\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_thumbnail\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_show_image_id\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_image_id\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_image_caption\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_image_caption\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_show_attach_image\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_attach_image\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_show_append_image\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_append_image\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_auto_append\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_auto_append\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_image_categories\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_image_categories\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_move_sidebar\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_move_sidebar\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if ($updated) {\r\n        		$GLOBALS[\'prefs\'] = get_prefs();\r\n        	}\r\n      	}\r\n      	if($install == \"remove\") {\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_thumbnail\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_image_id\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_image_caption\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_attach_image\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_append_image\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_auto_append\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_image_categories\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_move_sidebar\'\");\r\n      	}\r\n}\r\n// -------------------------------------------------------------\r\nfunction lam_image_uploader_gTxt($what, $atts = array()) {\r\n	$lang = array(\r\n		\'attach_image\'						=> \'Attach Article Image\',\r\n		\'append_image\'						=> \'Append Article Image\',\r\n		\'prefs\'							=> \'lam_image_uploader Preferences\',\r\n		\'preferences_removed\'					=> \'Preferences removed from database!\',\r\n		\'preferences_installed\'					=> \'Preferences added to database!\',\r\n		\'image_caption\'						=> \'Image caption?\',\r\n		\'remove\'						=> \'remove\',\r\n		\'auto_append\'						=> \'Automatically append article image id?\',\r\n		\'show_attach_image\'					=> \'Show \"Attach Article Image\" link?\',\r\n		\'show_append_image\'					=> \'Show \"Append Article Image\" link?\',\r\n		\'show_image_id\'						=> \'Show &lt;txp:image id /&gt; text?\',\r\n		\'show_thumbnail\'					=> \'Show Thumbnail?\',\r\n		\'image_categories\'					=> \'Allow image category assignment on upload?\',\r\n		\'move_sidebar\'						=> \'Move to left sidebar?\',\r\n		\'install\'						=> \'lam_image_uploader Install/Remove\',\r\n	);\r\n	return strtr($lang[$what], $atts);\r\n}','// 0.6c\r\nif (@txpinterface == \'admin\') {	\r\n	add_privs(\'lam_image_uploader_prefs\', \'1,2\');\r\n  	add_privs(\'handle_picture_upload_form\',\'1,2,3,4,5\');\r\n	add_privs(\'picture_upload_form\',\'1,2,3,4,5\');\r\n	register_callback(\"handle_picture_upload_form\", \"picture_upload_form\");\r\n  	register_callback(\"setup_picture_upload\", \"article\");\r\n	register_tab(\'extensions\', \'lam_image_uploader_prefs\', \'Image Uploader\');\r\n	register_callback(\'lam_image_uploader_prefs\', \'lam_image_uploader_prefs\');\r\n}\r\n\r\nfunction setup_picture_upload($event, $step) {\r\n	global $prefs;\r\n\r\n	echo \'<script type=\"text/javascript\">\r\n	var parentElement = document.getElementById(\"\';\r\n	if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n		echo \'article-col-1\");\';\r\n	} else { echo \'article-main\");\r\n		var p = document.createElement(\"p\");\r\n		var label = document.createElement(\"label\");\r\n		label.innerHTML = \"\'.gTxt(\'upload_image\').\'\";\r\n		label.setAttribute(\"id\",\"pictures-upload\");\r\n		label.setAttribute(\"name\",\"pictures-upload\");\r\n		p.appendChild(label);\r\n		parentElement.appendChild(p);\';\r\n	}\r\n	echo \'var iframe = document.createElement(\"iframe\");\r\n	iframe.setAttribute(\"id\", \"lam-pictures\");\r\n	iframe.setAttribute(\"name\",\"lam-pictures\");\r\n	iframe.setAttribute(\"border\",\"0\");\r\n	iframe.setAttribute(\"frameBorder\",\"0\");\r\n	iframe.setAttribute(\"src\", \"index.php?event=picture_upload_form\");\';\r\n	echo \'\r\n	iframe.style.width = \"100%\";\r\n	iframe.setAttribute(\"height\",\"235px\");\r\n	iframe.style.border = \"none\";\';\r\n	\r\n	if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n		echo \'parentElement.appendChild(iframe);\';\r\n	} else { echo \'p.appendChild(iframe);\';}\r\n	echo \'\r\n		function adjustIFrameSize(iframeWindow) {\r\n		if (iframeWindow.document.height) {\r\n			var iframeElement = document.getElementById (\"lam-pictures\");\r\n			iframeElement.style.height = iframeWindow.document.height + 25 + \"px\";\r\n			iframeElement.style.width = iframeWindow.document.width + \"px\";\r\n		} else if (document.all) {\r\n			var iframeElement = document.all[\"lam-pictures\"];\r\n			if (iframeWindow.document.compatMode &&\r\n			iframeWindow.document.compatMode != \"BackCompat\") {\r\n			iframeElement.style.height =\r\n			iframeWindow.document.documentElement.scrollHeight + 5 + \"px\";\r\n			iframeElement.style.width =\r\n			iframeWindow.document.documentElement.scrollWidth + 5 + \"px\";\r\n			} else {\r\n				iframeElement.style.height =\r\n				iframeWindow.document.body.scrollHeight + 5 + \"px\";\r\n				iframeElement.style.width = iframeWindow.document.body.scrollWidth\r\n				+ 5 + \"px\";\r\n			}\r\n		}\r\n	}\r\n	</script>\';\r\n}\r\n/// Inline Picture Upload\r\n// -------------------------------------------------------------\r\nfunction handle_picture_upload_form($attr) {\r\n	ob_start();\r\n	ob_end_clean();\r\n	global $prefs;\r\necho \'<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\r\n	\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\r\n<html>\r\n	<head>\r\n		<meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\">\r\n		<title>Picture Upload</title>\r\n		<link rel=\"stylesheet\" href=\"textpattern.css\" type=\"text/css\" media=\"screen\" title=\"no title\" charset=\"utf-8\">\r\n		<script type=\"text/javascript\" src=\"jquery.js\"></script>\r\n		<style type=\"text/css\" media=\"screen\">\r\n		body {\r\n			background:none !important;\r\n			background-color:inherit;\r\n		}\r\n      		form.upload-form {\r\n      			text-align:left;\r\n      			overflow:hidden;\r\n      			width:100%;\r\n      		}\r\n      		input.file {\r\n      			margin-top:0;\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n      			echo \'width:140px;\';\r\n      		}\r\n      		echo \'\r\n      		}\r\n      		input.alt {\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n      			echo \'width:140px;\';\r\n      		} else {\r\n      			echo \'width:400px;\';\r\n      			}\r\n      		echo \'}\r\n      		#image-category {\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n			echo \'max-width:160px;\';\r\n		} else {\r\n			}\r\n		echo \'}\r\n      		label {\r\n      			clear:both;\r\n        		display:block;\r\n                        margin-top:10px;\r\n      		}\r\n      		input.smallerbox {\r\n      			display:block;\r\n      			clear:both;\r\n      			margin-top:10px;\r\n      		}\r\n      		textarea {\';\r\n      		if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n      				echo \'width:140px;\';\r\n      			} else {\r\n      				echo \'width:400px;\';\r\n      			}\r\n      		echo \'\r\n      			height:80px;\r\n      		}\r\n      		.error {\r\n      			color:#fff;\r\n      			padding:5px 0;\r\n      			font-size:11px;\r\n      			background:#900;\r\n      			width:99%;\r\n      			clear:both;\r\n      		}\r\n      		input.result {\r\n      			border: 2px solid #11aa1b;\r\n      			margin: 20px 0;\r\n      			width: 146px;\r\n      		}\r\n      		#lam-attach, #lam-append {\r\n      			margin:20px 0;\r\n      		}\r\n		</style>\r\n		\r\n		<script type=\"text/javascript\">\r\n		function insertid(id, type) {\r\n			var MyElement = parent.document.getElementById(\"article-image\");\r\n			if (type == \"attach\") {\r\n				MyElement.value = id;\r\n			}\r\n			if (type == \"append\") {\r\n				if(MyElement.value == \"\") {\r\n					MyElement.value = id;\r\n				} else {\r\n					MyElement.value += \",\"+id;\r\n				}\r\n			}\r\n			return true;\r\n		}\r\n		$(document).ready(function() {\r\n			$(\"#lam_show_hide\").click(function () {\r\n				$(\"#lam_image_uploader\").toggle();\r\n   			 });\r\n 		 });\r\n		</script>\r\n	</head><body style=\"border:0;\" onload=\"parent.adjustIFrameSize(window);\">\';\r\n	if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n		echo \'<h3 class=\"plain\" style=\"text-align:left\"><a href=\"javascript:void(0);\" id=\"lam_show_hide\" onload>\'.gTxt(\'upload_image\').\'</a></h3><div id=\"lam_image_uploader\">\';\r\n	}\r\n	global $file_max_upload_size;\r\n	if (!$file_max_upload_size || intval($file_max_upload_size)==0) $file_max_upload_size = 2*(1024*1024);\r\n	$max_file_size = (intval($file_max_upload_size) == 0) ? \'\': intval($file_max_upload_size);\r\n	\r\n	if(isset($_FILES[\'thefile\'])) {\r\n		global $txpcfg, $extensions, $txp_user, $img_dir, $ext;\r\n		extract($txpcfg);\r\n		$meta = doSlash(gpsa(array(\'caption\', \'alt\', \'category\')));\r\n		$img_result = image_data2($_FILES[\'thefile\'], $meta);\r\n		\r\n		if(is_array($img_result) && isset($img_result[1])) {\r\n			if($prefs[\'lam_image_uploader_auto_append\'] ==\'1\') {\r\n				echo \'<script type=\"text/javascript\">\';\r\n				echo \"insertid($img_result[1], \'attach\');</script>\";\r\n			}\r\n			if($prefs[\'lam_image_uploader_show_thumbnail\'] == \'1\') {\r\n				echo \'<img src=\"\'.hu.$img_dir.\'/\'.$img_result[1].\'t\'.$ext;\r\n				if($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') {\r\n				echo \'\" width=\"150\" />\';\r\n				} else {\r\n					echo \'\" style=\"max-width:400px\" />\';\r\n				}\r\n			}\r\n			if($prefs[\'lam_image_uploader_show_image_id\'] == \'1\') {\r\n				echo \"<div><input type=\\\"text\\\" onfocus=\\\"this.select()\\\" name=\\\"show_image_id\\\" class=\\\"edit result\\\" value=\'<txp:image id=\\\"$img_result[1]\\\" />\' /></div>\";\r\n			}		\r\n			if($prefs[\'lam_image_uploader_show_attach_image\'] == \'1\') {\r\n				echo \"<div id=\\\"lam-attach\\\"><a href=\\\"javascript:void(0);\\\" onclick=\\\"insertid(\'$img_result[1]\',\'attach\');\\\">\".lam_image_uploader_gTxt(\'attach_image\').\"</a></div>\";\r\n			}\r\n			if($prefs[\'lam_image_uploader_show_append_image\'] == \'1\') {\r\n				echo \"<div id=\\\"lam-append\\\"><a href=\\\"javascript:void(0);\\\" onclick=\\\"insertid(\'$img_result[1]\',\'append\');\\\">\".lam_image_uploader_gTxt(\'append_image\').\"</a></div>\";\r\n			}\r\n		} else {\r\n			echo \'<div class=\"error\"><p>\'.$img_result.\'</p></div>\';\r\n		}\r\n	}\r\n	echo upload_form_for_page(\'picture\',\'file_insert\',\'picture_upload_form\', \'\',$max_file_size);\r\necho\'</div></body></html>\';\r\n	exit;\r\n}\r\n// -------------------------------------------------------------\r\nfunction image_data2($file , $meta = \'\', $id = \'\', $uploaded = true) {\r\n	global $txpcfg, $extensions, $txp_user, $prefs, $file_max_upload_size;\r\n	extract($txpcfg);\r\n\r\n	$name = $file[\'name\'];\r\n	$error = $file[\'error\'];\r\n	$file = $file[\'tmp_name\'];\r\n	if ($uploaded) {\r\n		$file = get_uploaded_file($file);\r\n		if ($file_max_upload_size < filesize($file)){\r\n			unlink($file);\r\n			return upload_get_errormsg(UPLOAD_ERR_FORM_SIZE);\r\n		}\r\n	}\r\n	list($w, $h, $extension) = getimagesize($file);\r\n	global $extensions;\r\n	$extensions = array(0,\'.gif\',\'.jpg\',\'.png\',\'.swf\');\r\n	define(\"IMPATH\",$prefs[\'path_to_site\'].\'/\'.$prefs[\'img_dir\'].\'/\');\r\n	include txpath.\'/lib/class.thumb.php\';\r\n	\r\n	if (($file !== false) && @$extensions[$extension]) {\r\n		global $ext;\r\n		$ext = $extensions[$extension];\r\n		$name = doSlash(substr($name, 0, strrpos($name, \'.\')).$ext);\r\n		if ($meta == false){\r\n			$meta = array(\'category\' => \'\',\'caption\' => \'\',\'alt\' => \'\');\r\n		}\r\n\r\n		extract($meta);\r\n		$q =\"name = \'$name\', ext = \'$ext\', w = $w, h = $h, alt = \'$alt\', caption = \'$caption\', category = \'$category\', date = now(), author = \'$txp_user\'\";\r\n\r\n		if (empty($id)) {\r\n			$rs = safe_insert(\'txp_image\',$q);\r\n			$id = $GLOBALS[\'ID\'] = mysql_insert_id();\r\n		} else {\r\n			$id = assert_int($id);\r\n			$rs = safe_update(\'txp_image\',$q,\"id = $id\");\r\n		}\r\n\r\n		if(!$rs) {\r\n			return gTxt(\'image_save_error\');\r\n		} else {\r\n			$newpath = IMPATH.$id.$ext;\r\n\r\n			if (shift_uploaded_file($file, $newpath) == false) {\r\n				$id = assert_int($id);\r\n				safe_delete(\'txp_image\',\"id = $id\");\r\n				safe_alter(\'txp_image\',\"auto_increment = $id\");\r\n\r\n				if (isset($GLOBALS[\'ID\'])) {\r\n					unset( $GLOBALS[\'ID\']);\r\n				}\r\n				return $newpath.sp.gTxt(\'upload_dir_perms\');\r\n			} else {\r\n				@chmod($newpath, 0644);\r\n\r\n				// Auto-generate a thumbnail using the last settings\r\n				if (isset($prefs[\'thumb_w\'], $prefs[\'thumb_h\'], $prefs[\'thumb_crop\'])) {\r\n					$t = new txp_thumb( $id );\r\n					$t->crop = ($prefs[\'thumb_crop\'] == \'1\');\r\n					$t->hint = \'0\';\r\n					if (is_numeric($prefs[\'thumb_w\'])) $t->width = $prefs[\'thumb_w\'];\r\n					if (is_numeric($prefs[\'thumb_h\'])) $t->height = $prefs[\'thumb_h\'];\r\n					$t->write();\r\n				}\r\n				$message = gTxt(\'image_uploaded\', array(\'{name}\' => $name));\r\n				return array($message, $id);\r\n			}\r\n		}\r\n	} else {\r\n		if ($file === false) {\r\n			return upload_get_errormsg($error);\r\n		} else {\r\n			return gTxt(\'only_graphic_files_allowed\');\r\n		}\r\n	}\r\n}\r\n// -------------------------------------------------------------\r\nfunction upload_form_for_page($pophelp, $step, $event, $id = \'\', $max_file_size = \'1000000\', $label_id = \'\', $class = \'upload-form\') {\r\n	global $sort, $dir, $page, $search_method, $crit, $prefs;\r\n	$class = ($class) ? \' class=\"\'.$class.\'\"\' : \'\';\r\n	$categories = getTree(\"root\",\"image\");\r\n	$label_id = ($label_id) ? $label_id : $event.\'-upload\';\r\n	$lam_image_file = ($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') ? fInput(\'file\',\'thefile\',\'\',\'file edit\',\'\',\'\',\'11\') : fInput(\'file\',\'thefile\',\'\',\'file edit\',\'\',\'\',\'15\');\r\n	$lam_image_alt = ($prefs[\'lam_image_uploader_move_sidebar\'] == \'1\') ? fInput(\'text\', \'alt\', \'\', \'alt edit\',\'\',\'\',\'22\') : fInput(\'text\', \'alt\', \'\', \'alt edit\');\r\n	$lam_image_caption = ($prefs[\'lam_image_uploader_image_caption\'] == \'1\') ? \'<label for=\"caption\">\'.gTxt(\'caption\').\'</label>\'.\r\n	\'<textarea id=\"caption\" name=\"caption\" cols=\"18\" rows=\"5\"></textarea>\' : \'\';\r\n	$lam_image_categories = ($prefs[\'lam_image_uploader_image_categories\'] == \'1\') ? \'<label for=\"category\">\'.gTxt(\'image_category\').\'</label>\'.treeSelectInput(\'category\', $categories, \'\', \'image-category\') : \'\';\r\n	\r\n	return n.n.\'<form\'.$class.\' method=\"post\" enctype=\"multipart/form-data\" action=\"index.php\">\'.\r\n	n.\'<div>\'.\r\n	(!empty($max_file_size)? n.hInput(\'MAX_FILE_SIZE\', $max_file_size): \'\').\r\n	n.eInput($event).n.sInput($step).n.hInput(\'id\', $id).n.hInput(\'sort\', $sort).n.hInput(\'dir\', $dir).n.hInput(\'page\', $page).\r\n	n.hInput(\'crit\', $crit).\r\n	$lam_image_file.$lam_image_categories.\'<label for=\"alt\">\'.gTxt(\'alt_text\').\'</label>\'.\r\n	$lam_image_alt.$lam_image_caption.\r\n	fInput(\'submit\', \'\', gTxt(\'upload\'), \'smallerbox\').\r\n	n.\'</div>\'.\r\n	n.\'</form>\';\r\n}\r\n// -------------------------------------------------------------\r\nfunction lam_image_uploader_prefs($event, $step) {\r\n	global $prefs;\r\n	switch ($step) {\r\n	case \'remove\':\r\n		$lam_status = lam_image_uploader_gTxt(\'preferences_removed\');\r\n		break;\r\n	case \'install\':\r\n		$lam_status = lam_image_uploader_gTxt(\'preferences_installed\');\r\n		break;\r\n	case \'update\':\r\n		$lam_status = gTxt(\'preferences_saved\');\r\n		break;\r\n	default:\r\n		$lam_status = \'\';\r\n	}\r\n	\r\n      	pagetop(lam_image_uploader_gTxt(\'prefs\'), $lam_status);\r\n	$checkInstalled = fetch(\'event\',\'txp_prefs\',\'name\',\'lam_image_uploader_show_thumbnail\');\r\n	\r\n      	if ($step == \'update\') {\r\n      		extract(doSlash(psas(array(\r\n      			\'show_thumbnail\', \'show_image_id\', \'image_caption\', \'show_attach_image\', \'show_append_image\', \'auto_append\', \'image_categories\', \'move_sidebar\'\r\n      		))));\r\n      		$show_thumbnail  = ($show_thumbnail == \'1\') ? $show_thumbnail : \'0\';\r\n      		$show_image_id = ($show_image_id == \'1\') ? $show_image_id : \'0\';\r\n      		$image_caption = ($image_caption == \'1\') ? $image_caption : \'0\';\r\n      		$show_attach_image  = ($show_attach_image == \'1\') ? $show_attach_image : \'0\';\r\n      		$show_append_image = ($show_append_image == \'1\') ? $show_append_image : \'0\';\r\n      		$auto_append  = ($auto_append == \'1\') ? $auto_append : \'0\';\r\n      		$image_categories = ($image_categories == \'1\') ? $image_categories : \'0\';\r\n      		$move_sidebar = ($move_sidebar == \'1\') ? $move_sidebar : \'0\';\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_thumbnail\'\", \"name = \'lam_image_uploader_show_thumbnail\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_image_id\'\", \"name = \'lam_image_uploader_show_image_id\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$image_caption\'\", \"name = \'lam_image_uploader_image_caption\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_attach_image\'\", \"name = \'lam_image_uploader_show_attach_image\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$show_append_image\'\", \"name = \'lam_image_uploader_show_append_image\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$auto_append\'\", \"name = \'lam_image_uploader_auto_append\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$image_categories\'\", \"name = \'lam_image_uploader_image_categories\'\");\r\n      		safe_update(\'txp_prefs\', \"val = \'$move_sidebar\'\", \"name = \'lam_image_uploader_move_sidebar\'\");\r\n      		$prefs = get_prefs();\r\n      	}\r\n      	if($step == \'remove\') {\r\n      		lam_image_uploader_install(\'remove\');\r\n      		$checkInstalled = fetch(\'event\',\'txp_prefs\',\'name\',\'lam_image_uploader_show_thumbnail\');\r\n      	} else if($step == \'install\') {\r\n      		lam_image_uploader_install(\'install\');\r\n      		$checkInstalled = fetch(\'event\',\'txp_prefs\',\'name\',\'lam_image_uploader_show_thumbnail\');\r\n      	}\r\n	if($checkInstalled) {\r\n      	echo n.n.\'<div style=\"margin: 3em auto auto auto; width: 30em;\">\'.\r\n      	n.n.hed(lam_image_uploader_gTxt(\'prefs\'), \'1\').\r\n      	n.n.form(\r\n      		n.eInput(\'lam_image_uploader_prefs\').\r\n      		n.sInput(\'update\').\r\n      		n.n.tag(\r\n      			n.n.tag(gTxt(\'edit_preferences\'), \'legend\').\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_thumbnail\').br.\r\n      				n.yesnoRadio(\'show_thumbnail\', $prefs[\'lam_image_uploader_show_thumbnail\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_image_id\').br.\r\n      				n.yesnoRadio(\'show_image_id\', $prefs[\'lam_image_uploader_show_image_id\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'image_caption\').br.\r\n      				n.yesnoRadio(\'image_caption\', $prefs[\'lam_image_uploader_image_caption\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_attach_image\').br.\r\n      				n.yesnoRadio(\'show_attach_image\', $prefs[\'lam_image_uploader_show_attach_image\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'show_append_image\').br.\r\n      				n.yesnoRadio(\'show_append_image\', $prefs[\'lam_image_uploader_show_append_image\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'auto_append\').br.\r\n      				n.yesnoRadio(\'auto_append\', $prefs[\'lam_image_uploader_auto_append\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'image_categories\').br.\r\n      				n.yesnoRadio(\'image_categories\', $prefs[\'lam_image_uploader_image_categories\'])\r\n      			).\r\n      			n.n.graf(\r\n      				lam_image_uploader_gTxt(\'move_sidebar\').br.\r\n      				n.yesnoRadio(\'move_sidebar\', $prefs[\'lam_image_uploader_move_sidebar\'])\r\n      			)\r\n      		, \'fieldset\').\r\n      		n.n.fInput(\'submit\', \'update\', \'Update\', \'smallerbox\')\r\n	).n.n.\'</div>\';\r\n	}\r\n	echo n.n.\'<div style=\"margin: 3em auto auto auto; width: 30em;\">\'.\r\n      	n.n.hed(lam_image_uploader_gTxt(\'install\'), \'1\');\r\n      	echo \'<form method=\"post\" action=\"index.php\">\';\r\n      	echo hInput(\'event\',\'lam_image_uploader_prefs\');\r\n      	if(empty($checkInstalled)) {  \r\n      		echo fInput(\'submit\', \'step\', \'install\', \'smallerbox\');\r\n      	} else {\r\n      		echo fInput(\'submit\', \'step\', \'remove\', \'smallerbox\');\r\n      		}\r\n      	echo \'</form>\';\r\n}\r\n// -------------------------------------------------------------\r\nfunction lam_image_uploader_install($install) {\r\n      	global $prefs;\r\n      	$updated = false;\r\n      	$settings = \"prefs_id = 1, type = 2, event = \'admin\', position = 0\";\r\n	if($install == \'install\') {\r\n        	if (!isset($prefs[\'lam_image_uploader_show_thumbnail\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_thumbnail\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_show_image_id\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_image_id\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_image_caption\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_image_caption\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_show_attach_image\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_attach_image\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_show_append_image\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_show_append_image\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_auto_append\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_auto_append\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_image_categories\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_image_categories\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if (!isset($prefs[\'lam_image_uploader_move_sidebar\'])) {\r\n        		safe_insert(\'txp_prefs\', \"name = \'lam_image_uploader_move_sidebar\', val = \'1\', html = \'yesnoradio\', $settings\");\r\n        		$updated = true;\r\n        	}\r\n        	if ($updated) {\r\n        		$GLOBALS[\'prefs\'] = get_prefs();\r\n        	}\r\n      	}\r\n      	if($install == \"remove\") {\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_thumbnail\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_image_id\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_image_caption\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_attach_image\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_show_append_image\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_auto_append\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_image_categories\'\");\r\n      		safe_delete(\'txp_prefs\',\"name = \'lam_image_uploader_move_sidebar\'\");\r\n      	}\r\n}\r\n// -------------------------------------------------------------\r\nfunction lam_image_uploader_gTxt($what, $atts = array()) {\r\n	$lang = array(\r\n		\'attach_image\'						=> \'Attach Article Image\',\r\n		\'append_image\'						=> \'Append Article Image\',\r\n		\'prefs\'							=> \'lam_image_uploader Preferences\',\r\n		\'preferences_removed\'					=> \'Preferences removed from database!\',\r\n		\'preferences_installed\'					=> \'Preferences added to database!\',\r\n		\'image_caption\'						=> \'Image caption?\',\r\n		\'remove\'						=> \'remove\',\r\n		\'auto_append\'						=> \'Automatically append article image id?\',\r\n		\'show_attach_image\'					=> \'Show \"Attach Article Image\" link?\',\r\n		\'show_append_image\'					=> \'Show \"Append Article Image\" link?\',\r\n		\'show_image_id\'						=> \'Show &lt;txp:image id /&gt; text?\',\r\n		\'show_thumbnail\'					=> \'Show Thumbnail?\',\r\n		\'image_categories\'					=> \'Allow image category assignment on upload?\',\r\n		\'move_sidebar\'						=> \'Move to left sidebar?\',\r\n		\'install\'						=> \'lam_image_uploader Install/Remove\',\r\n	);\r\n	return strtr($lang[$what], $atts);\r\n}','a1805f5b260589ea68de2ed20910a27e',1,5,0),('zem_contact_reborn',1,'TXP Community','http://forum.textpattern.com/viewtopic.php?id=23728','4.0.3.20','Form mailer for Textpattern',' <style>\n   li code {font-weight: bold;}\n   pre {padding: 0.5em 1em; background: #eee; border: 1px dashed #ccc;}\n   h1, h2, h3, h3 code {font-family: sans-serif; font-weight: bold;}\n   h1, h2, h3 {margin-left: -1em;}\n   h2, h3 {margin-top: 2em;}\n   h1 {font-size: 3em;}\n   h2 {font-size: 2em;}\n   h3 {font-size: 1.5em;}\n   li a code {font-weight: normal;}\n   .required, .warning {color:red;}\n </style>\n\n	<h1 id=\"top\">Zem Contact Reborn</h1>\n\n	<p>Please reports bugs and problems with this plugin in <a href=\"http://forum.textpattern.com/viewtopic.php?id=23728\">this forum thread</a>.</p>\n\n	<p class=\"required\">This plugin requires a separate language plugin called <code>zem_contact_lang</code> to be installed and activated to work properly.</p>\n\n	<h2 id=\"contents\">Contents</h2>\n\n	<ul>\n		<li><a href=\"#features\">Features</a></li>\n		<li><a href=\"#start\">Getting started</a>\n	<ul>\n		<li><a href=\"#contactform\">Contact form</a></li>\n		<li><a href=\"#sendarticle\">Send article</a></li>\n	</ul></li>\n		<li><a href=\"#tags\">Tags</a>\n	<ul>\n		<li><a href=\"#zc\"> <code>&lt;txp:zem_contact /&gt;</code> </a></li>\n		<li><a href=\"#zc_text\"> <code>&lt;txp:zem_contact_text /&gt;</code> </a></li>\n		<li><a href=\"#zc_email\"> <code>&lt;txp:zem_contact_email /&gt;</code> </a></li>\n		<li><a href=\"#zc_textarea\"> <code>&lt;txp:zem_contact_textarea /&gt;</code> </a></li>\n		<li><a href=\"#zc_submit\"> <code>&lt;txp:zem_contact_submit /&gt;</code> </a></li>\n		<li><a href=\"#zc_select\"> <code>&lt;txp:zem_contact_select /&gt;</code> </a></li>\n		<li><a href=\"#zc_checkbox\"> <code>&lt;txp:zem_contact_checkbox /&gt;</code> </a></li>\n		<li><a href=\"#zc_radio\"> <code>&lt;txp:zem_contact_radio /&gt;</code> </a></li>\n		<li><a href=\"#zc_secret\"> <code>&lt;txp:zem_contact_secret /&gt;</code> </a></li>\n		<li><a href=\"#zc_server_info\"> <code>&lt;txp:zem_contact_serverinfo /&gt;</code> </a></li>\n		<li><a href=\"#zc_send_article\"> <code>&lt;txp:zem_contact_send_article /&gt;</code> </a></li>\n	</ul></li>\n		<li><a href=\"#advanced\">Advanced examples</a>\n	<ul>\n		<li><a href=\"#show_error\">Separate input and error forms</a></li>\n		<li><a href=\"#subject_form\">User selectable subject field</a></li>\n		<li><a href=\"#to_form\">User selectable recipient, without showing email addresses</a></li>\n	</ul></li>\n		<li><a href=\"#styling\">Styling</a></li>\n		<li><a href=\"#history\">History</a></li>\n		<li><a href=\"#credits\">Credits</a></li>\n		<li><a href=\"#api\">Plugin <span class=\"caps\">API</span> and callback events</a></li>\n	</ul>\n\n	<h2 id=\"features\">Features</h2>\n\n	<ul>\n		<li>Arbitrary text fields can be specified, with min/max/required settings for validation.</li>\n		<li>Email address validation, including a check for a valid MX record (Unix only).</li>\n		<li>Safe escaping of input data.</li>\n		<li><span class=\"caps\">UTF</span>-8 safe.</li>\n		<li>Accessible form layout, including <code>&lt;label&gt;</code>, <code>&lt;legend&gt;</code> and <code>&lt;fieldset&gt;</code> tags.</li>\n		<li>Various classes and ids to allow easy styling of all parts of the form.</li>\n		<li>A separate language plug-in to enable easy localisation.</li>\n		<li>Spam prevention <span class=\"caps\">API</span> (used by Tranquillo&#8217;s <code>pap_contact_cleaner</code> plugin).</li>\n	</ul>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h2 id=\"start\">Getting started</h2>\n\n	<h3 id=\"contactform\">Contact form</h3>\n\n	<p>The simplest form is shown below, which produces a default form with Name, Email and Message fields. Email will be delivered to recipient@example.com, with the user&#8217;s supplied email as the &#8220;From:&#8221; address.</p>\n\n<pre><code>&lt;txp:zem_contact to=&quot;recipient@example.com&quot; /&gt;\n</code></pre>\n\n	<p>To specify fields explicitly, use something like this:</p>\n\n<pre><code>&lt;txp:zem_contact to=&quot;recipient@example.com&quot;&gt;\n  &lt;txp:zem_contact_email /&gt;\n  &lt;txp:zem_contact_text label=&quot;Phone&quot; min=7 max=15/&gt;\n  &lt;txp:zem_contact_textarea label=&quot;Your question&quot; /&gt;\n  &lt;txp:zem_contact_submit label=&quot;Send&quot; /&gt;\n&lt;/txp:zem_contact&gt;\n</code></pre>\n\n	<p>Alternatively, place the field specifications in a Textpattern form, and call it like this:</p>\n\n<pre><code>&lt;txp:zem_contact to=&quot;recipient@example.com&quot; form=&quot;mycontactform&quot; /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"sendarticle\">Send article</h3>\n\n	<p>Within the context of an individual article, this plugin can be used to send the article (or excerpt, if it exists) to an email address specified by the visitor. This requires at least two tags:\n	<ul>\n		<li><code>zem_contact</code>, to create form that is initially hidden by setting the <code>send_article</code> attribute.</li>\n		<li><code>zem_contact_send_article</code>, to create a &#8216;send article&#8217; link which reveals the aforementioned form when clicked.</li>\n	</ul></p>\n\n<pre><code>&lt;txp:zem_contact send_article=&quot;1&quot; /&gt;\n&lt;txp:zem_contact_send_article /&gt;\n</code></pre>\n\n	<p>By default the form contains fields for your name and email address, the recipient&#8217;s email address and a personal message, but similar to contact forms you can create your own form layout. Some things you need to know:\n	<ul>\n		<li>Set the <code>send_article</code> attribute to <code>1</code> in the <code>zem_contact</code> tag.</li>\n		<li>Use a <code>zem_contact_email</code> tag with the <code>send_article</code> attribute set to <code>1</code>. This field will be used as the recipient email address.</li>\n	</ul></p>\n\n<pre><code>&lt;txp:zem_contact to=&quot;you@example.com&quot; send_article=&quot;1&quot;&gt;\n  &lt;txp:zem_contact_email label=&quot;Recipient Email&quot; send_article=&quot;1&quot; /&gt;\n  &lt;txp:zem_contact_email label=&quot;Your Email&quot; /&gt;\n  &lt;txp:zem_contact_submit label=&quot;Send Article&quot; /&gt;\n&lt;/txp:zem_contact&gt;\n</code>\n<code>&lt;txp:zem_contact_send_article /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h2 id=\"tags\">Tags</h2>\n\n	<p><a href=\"#zc\"><code>&lt;txp:zem_contact /&gt;</code></a> produces a flexible, customisable email contact form. It is intended for use as an enquiry form for commercial and private sites, and includes several features to help reduce common problems with such forms (invalid email addresses, missing information).</p>\n\n	<p><a href=\"#zc_send_article\"><code>&lt;txp:zem_contact_send_article /&gt;</code></a> can be used to create a &#8220;send article&#8221; link within an article form, connecting it to the contact form.</p>\n\n	<p>All other tags provided by this plugin can only be used inside a <code>&lt;txp:zem_contact&gt;</code> &#8230; <code>&lt;/txp:zem_contact&gt;</code> container tag or in a Textpattern form used as the <code>form</code> attribute in the <code>&lt;txp:zem_contact /&gt;</code> tag.</p>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc\"><code>&lt;txp:zem_contact /&gt;</code></h3>\n\n	<p>May be used as a self-closing or container tag. Place this where you want the input form to go. Status and error messages, if any, will be displayed before the form.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>to=&quot;email address&quot;</code> <span class=\"required\">required</span><br />\nRecipient email address.</li>\n		<li><code>to_form=&quot;form name&quot;</code><br />\nUse specified form (overrides <strong>to</strong> attribute).</li>\n	</ul>\n\n	<ul>\n		<li><code>from=&quot;email address&quot;</code><br />\nEmail address used in the &#8220;From:&#8221; field when sending email. Defaults to the sender&#8217;s email address. If specified, the sender&#8217;s email address will be placed in the &#8220;Reply-To:&#8221; field instead.</li>\n		<li><code>from_form=&quot;form name&quot;</code><br />\nUse specified form (overrides <strong>from</strong> attribute).</li>\n	</ul>\n\n	<ul>\n		<li><code>subject=&quot;subject text&quot;</code><br />\nSubject used when sending an email. Default is the site name.</li>\n		<li><code>subject_form=&quot;form name&quot;</code><br />\nUse specified form (overrides <strong>subject</strong> attribute).</li>\n	</ul>\n\n	<ul>\n		<li><code>thanks=&quot;text&quot;</code><br />\nMessage shown after successfully submitting a message. Default is <strong>Thank you, your message has been sent</strong>.</li>\n		<li><code>thanks_form=&quot;form name&quot;</code><br />\nUse specified form (overrides <strong>thanks</strong> attribute).</li>\n		<li><code>redirect=&quot;URL&quot;</code><br />\nRedirect to specified <span class=\"caps\">URL</span> (overrides <strong>thanks</strong> and <strong>thanks_form</strong> attributes). <span class=\"caps\">URL</span> must be relative to the Textpattern Site <span class=\"caps\">URL</span>. Example: <em>redirect=&#8220;monkey&#8221;</em> would redirect to http://example.com/monkey.</li>\n	</ul>\n\n	<ul>\n		<li><code>label=&quot;text&quot;</code><br />\nLabel for the contact form. If set to an empty string, display of the fieldset and legend tags will be suppressed. Default is <strong>Contact</strong>.</li>\n		<li><code>send_article=&quot;boolean&quot;</code><br />\nWhether to use this form to <a href=\"#article\">send an article</a>. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>0</strong> (no).</li>\n		<li><code>copysender=&quot;boolean&quot;</code><br />\nWhether to send a copy of the email to the sender&#8217;s address. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>0</strong> (no).</li>\n	</ul>\n\n	<ul>\n		<li><code>form=&quot;form name&quot;</code><br />\nUse specified form, containing the layout of the contact form fields.</li>\n		<li><code>show_input=&quot;boolean&quot;</code><br />\n Whether to display the form input fields. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>1</strong> (yes).</li>\n		<li><code>show_error=&quot;boolean&quot;</code><br />\n Whether to display error and status messages. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>1</strong> (yes).</li>\n	</ul>\n\n	<h4>Examples</h4>\n\n	<p>See <a href=\"#contactform\">Getting started</a> and <a href=\"#advanced\">Advanced examples</a>.</p>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_text\"><code>&lt;txp:zem_contact_text /&gt;</code></h3>\n\n	<p>Creates a text input field and corresponding <code>&lt;label&gt;</code> tag. The input value will be included in the email, preceded by the label.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>label=&quot;text&quot;</code><br />\nText label displayed to the user. Default is <strong>Text</strong>.</li>\n		<li><code>name=&quot;value&quot;</code><br />\nField name, as used in the <span class=\"caps\">HTML</span> input tag.</li>\n		<li><code>break=&quot;tag&quot;</code><br />\nBreak tag between the label and input field. Default is <code>&lt;br /&gt;</code>. Use <code>break=&quot;&quot;</code> to put the label and input field on the same line.</li>\n		<li><code>default=&quot;value&quot;</code><br />\nDefault value when no input is provided.</li>\n		<li><code>min=&quot;integer&quot;</code><br />\nMinimum input length in characters. Default is <strong>0</strong>.</li>\n		<li><code>max=&quot;integer&quot;</code><br />\nMaximum input length in characters. Default is <strong>100</strong>.</li>\n		<li><code>size=&quot;integer&quot;</code><br />\nSize of the input field as displayed to the user.</li>\n		<li><code>required=&quot;boolean&quot;</code><br />\nWhether this text field must be filled out. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>1</strong> (yes).</li>\n	</ul>\n\n	<h4>Example</h4>\n\n<pre><code>&lt;txp:zem_contact_text label=&quot;Your name&quot; /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_email\"><code>&lt;txp:zem_contact_email /&gt;</code></h3>\n\n	<p>Input field for user&#8217;s email address.</p>\n\n	<p>The entered email address will automatically be validated to make sure it is of the form &#8220;abc@xxx.yyy[.zzz]&#8221;. On non-Windows servers, a test will be done to verify that an A or MX record exists for the domain. Neither test prevents spam, but it does help detecting accidental typing errors.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>label=&quot;text&quot;</code><br />\nText label displayed to the user. Default is <strong>Email</strong>.</li>\n		<li><code>name=&quot;value&quot;</code><br />\nField name, as used in the <span class=\"caps\">HTML</span> input tag.</li>\n		<li><code>break=&quot;tag&quot;</code><br />\nBreak tag between the label and input field. Default is <code>&lt;br /&gt;</code>. Use <code>break=&quot;&quot;</code> to put the label and input field on the same line.</li>\n		<li><code>default=&quot;value&quot;</code><br />\nDefault value when no input is provided.</li>\n		<li><code>min=&quot;integer&quot;</code><br />\nMinimum input length in characters. Default is <strong>0</strong>.</li>\n		<li><code>max=&quot;integer&quot;</code><br />\nMaximum input length in characters. Default is <strong>100</strong>.</li>\n		<li><code>size=&quot;integer&quot;</code><br />\nSize of the input field as displayed to the user.</li>\n		<li><code>required=&quot;boolean&quot;</code><br />\nWhether this text field must be filled out. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>1</strong> (yes).</li>\n		<li><code>send_article=&quot;boolean&quot;</code><br />\nWhether this field is used as the recipient email address when using the send_article function. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>0</strong> (no).</li>\n	</ul>\n\n	<h4>Example</h4>\n\n<pre><code>&lt;txp:zem_contact_email label=&quot;Your email address&quot; /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_textarea\"><code>&lt;txp:zem_contact_textarea /&gt;</code></h3>\n\n	<p>Creates a textarea.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>label=&quot;text&quot;</code><br />\nText label displayed to the user. Default is <strong>Message</strong>.</li>\n		<li><code>name=&quot;value&quot;</code><br />\nField name, as used in the <span class=\"caps\">HTML</span> input tag.</li>\n		<li><code>break=&quot;tag&quot;</code><br />\nBreak tag between the label and input field. Default is <code>&lt;br /&gt;</code>. Use <code>break=&quot;&quot;</code> to put the label and input field on the same line.</li>\n		<li><code>default=&quot;value&quot;</code><br />\nDefault value when no input is provided.</li>\n		<li><code>cols=&quot;integer&quot;</code><br />\nColumn width. Default is <strong>58</strong>.</li>\n		<li><code>rows=&quot;integer&quot;</code><br />\nRow height. Default is <strong>8</strong>.</li>\n		<li><code>min=&quot;integer&quot;</code><br />\nMinimum input length in characters. Default is <strong>0</strong>.</li>\n		<li><code>max=&quot;integer&quot;</code><br />\nMaximum input length in characters. Default is <strong>10000</strong>.</li>\n		<li><code>required=&quot;boolean&quot;</code><br />\nWhether this text field must be filled out. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>1</strong> (yes).</li>\n	</ul>\n\n	<h4>Example</h4>\n\n	<p>Textarea that is 40 chars wide, 10 lines high, with a customized label:</p>\n\n<pre><code>&lt;txp:zem_contact_textarea cols=&quot;40&quot; rows=&quot;10&quot; label=&quot;Your question&quot; /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_submit\"><code>&lt;txp:zem_contact_submit /&gt;</code></h3>\n\n	<p>Creates a submit button.<br />\nWhen used as a container tag, a &#8220;button&#8221; element will be used instead of an &#8220;input&#8221; element.</p>\n\n	<h4>Attributes:</h4>\n\n	<ul>\n		<li><code>label=&quot;text&quot;</code><br />\nText shown on the submit button. Default is &#8220;Send&#8221;.</li>\n		<li><code>button=&quot;boolean&quot;</code><br />\n<em>Deprecated. Use a container tag if you want a button element.</em></li>\n	</ul>\n\n	<h4>Examples</h4>\n\n	<p>Standard submit button:</p>\n\n<pre><code>&lt;txp:zem_contact_submit /&gt;\n</code></pre>\n\n	<p>Submit button with your own text:</p>\n\n<pre><code>&lt;txp:zem_contact_submit label=&quot;Send&quot; /&gt;\n</code></pre>\n\n	<p>Usage as a container tag, which allows you to use Textpattern tags and <span class=\"caps\">HTML</span> markup in the submit button:</p>\n\n<pre><code>&lt;txp:zem_contact_submit&gt;&lt;strong&gt;Send&lt;/strong&gt; question&lt;/txp:zem_contact_submit&gt;\n</code></pre>\n\n<pre><code>&lt;txp:zem_contact_submit&gt;&lt;img src=&quot;path/to/img.png&quot; alt=&quot;submit&quot;&gt;&lt;/txp:zem_contact_submit&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_select\"><code>&lt;txp:zem_contact_select /&gt;</code></h3>\n\n	<p>Creates a drop-down selection list.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>list=&quot;comma-separated values&quot;</code> <span class=\"required\">required</span><br />\nList of items to show in the select box.</li>\n		<li><code>selected=&quot;value&quot;</code><br />\nList item that is selected by default.</li>\n		<li><code>label=&quot;text&quot;</code><br />\nText label displayed to the user. Default is <strong>Option</strong>.</li>\n		<li><code>name=&quot;value&quot;</code><br />\nField name, as used in the <span class=\"caps\">HTML</span> input tag.</li>\n		<li><code>break=&quot;tag&quot;</code><br />\nBreak tag between the label and input field. Default is <code>&lt;br /&gt;</code>. Use <code>break=&quot;&quot;</code> to put the label and input field on the same line.</li>\n		<li><code>delimiter=&quot;character&quot;</code><br />\nSeparator character used in the <strong>list</strong> attribute. Default is <strong>,</strong> (comma).</li>\n		<li><code>required=&quot;boolean&quot;</code><br />\nWhether a non-empty option must be selected. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>1</strong> (yes).</li>\n	</ul>\n\n	<h4>Examples</h4>\n\n	<p>Select list labeled &#8216;Department&#8217;, containing three options and a blank option (due to the comma before &#8216;Marketing&#8217;) shown by default, forcing the user to make a selection.</p>\n\n<pre><code>&lt;txp:zem_contact_select label=&quot;Department&quot; list=&quot;,Marketing,Sales,Support&quot; /&gt;\n</code></pre>\n\n	<p>Select list containing three options with &#8216;Marketing&#8217; selected by default.</p>\n\n<pre><code>&lt;txp:zem_contact_select list=&quot;Marketing,Sales,Support&quot; selected=&quot;Marketing&quot; /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_checkbox\"><code>&lt;txp:zem_contact_checkbox /&gt;</code></h3>\n\n	<p>Creates a check box.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>label=&quot;text&quot;</code><br />\nText label displayed to the user. Default is <strong>Checkbox</strong>.</li>\n		<li><code>name=&quot;value&quot;</code><br />\nField name, as used in the <span class=\"caps\">HTML</span> input tag.</li>\n		<li><code>break=&quot;tag&quot;</code><br />\nBreak tag between the label and input field. Default is <code>&lt;br /&gt;</code>. Use <code>break=&quot;&quot;</code> to put the label and input field on the same line.</li>\n		<li><code>checked=&quot;boolean&quot;</code><br />\nWhether this box is checked when first displayed. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is &#8220;0&#8221; (no).</li>\n		<li><code>required=&quot;boolean&quot;</code><br />\nWhether this checkbox must be filled out. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>1</strong> (yes).</li>\n	</ul>\n\n	<h4>Examples</h4>\n\n	<p>Shrink-wrap agreement which must be checked by the user before the email will be sent.</p>\n\n<pre><code>&lt;txp:zem_contact_checkbox label=&quot;I accept the terms and conditions&quot; /&gt;\n</code></pre>\n\n	<p>Optional checkboxes:</p>\n\n<pre><code>Select which operating systems are you familiar with:&lt;br /&gt;\n&lt;txp:zem_contact_checkbox label=&quot;Windows&quot; required=&quot;0&quot; /&gt;&lt;br /&gt;\n&lt;txp:zem_contact_checkbox label=&quot;Unix/Linux/BSD&quot; required=&quot;0&quot; /&gt;&lt;br /&gt;\n&lt;txp:zem_contact_checkbox label=&quot;MacOS&quot; required=&quot;0&quot; /&gt;&lt;br /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_radio\"><code>&lt;txp:zem_contact_radio /&gt;</code></h3>\n\n	<p>Creates a radio button.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>group=&quot;text&quot;</code> <span class=\"required\">required</span><br />\nText used in the email to describe this group of radio buttons. This attribute value is remembered for subsequent radio buttons, so you only have to set it on the first radio button of a group. Default is <strong>Radio</strong>.</li>\n		<li><code>label=&quot;text&quot;</code> <span class=\"required\">required</span><br />\nText label displayed to the user as radio button option.</li>\n		<li><code>name=&quot;value&quot;</code><br />\nField name, as used in the <span class=\"caps\">HTML</span> input tag. This attribute value is remembered for subsequent radio buttons, so you only have to set it on the first radio button of a group. If it hasn&#8217;t been set at all, it will be derived from the <code>group</code> attribute.</li>\n		<li><code>break=&quot;tag&quot;</code><br />\nBreak tag between the label and field. Default is a space.</li>\n		<li><code>checked=&quot;boolean&quot;</code><br />\nWhether this radio option is checked when the form is first displayed. Available values: <strong>1</strong> (yes), <strong>0</strong> (no). Default is <strong>0</strong> (no).</li>\n	</ul>\n\n	<h4>Example</h4>\n\n	<p>Group mutually exclusive radio buttons by setting the <code>group</code> attribute on the first radio button in a group. Only the chosen radio button from each group will be used in the email message. The message will be output in the form <strong>group: label</strong> for each of the chosen radio buttons.</p>\n\n<pre><code>&lt;txp:zem_contact_radio label=&quot;Medium&quot; group=&quot;I like my steak&quot; /&gt;\n&lt;txp:zem_contact_radio label=&quot;Rare&quot; /&gt;\n&lt;txp:zem_contact_radio label=&quot;Well done&quot; /&gt;\n</code>\n<code>&lt;txp:zem_contact_radio label=&quot;Wine&quot; group=&quot;With a glass of&quot; /&gt;\n&lt;txp:zem_contact_radio label=&quot;Beer&quot; /&gt;\n&lt;txp:zem_contact_radio label=&quot;Water&quot; /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_secret\"><code>&lt;txp:zem_contact_secret /&gt;</code></h3>\n\n	<p>This tag has no effect on the form or <span class=\"caps\">HTML</span> output, but will include additional information in the email. It can be used as a self-closing tag or as a container tag.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>name=&quot;text&quot;</code><br />\nUsed internally. Set this only if you have multiple &#8216;secret&#8217; form elements with identical labels.</li>\n		<li><code>label=&quot;text&quot;</code><br />\nUsed to identify the field in the email. Default is <strong>Secret</strong>.</li>\n		<li><code>value=&quot;value&quot;</code><br />\nSome text you want to add to the email.</li>\n	</ul>\n\n	<h4>Examples</h4>\n\n	<p>Usage as a self-closing tag</p>\n\n<pre><code>&lt;txp:zem_contact_secret value=&quot;The answer is 42&quot; /&gt;\n</code></pre>\n\n	<p>Usage as a container tag</p>\n\n<pre><code>&lt;txp:zem_contact_secret label=&quot;Dear user&quot;&gt;\n  Please provide a useful example for this tag!\n&lt;/txp:zem_contact_secret&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_serverinfo\"><code>&lt;txp:zem_contact_serverinfo /&gt;</code></h3>\n\n	<p>This tag has no effect on the form or <span class=\"caps\">HTML</span> output, but will include additional information in the email based on the <span class=\"caps\">PHP</span> $_SERVER variable.</p>\n\n	<h4>Attributes</h4>\n\n	<ul>\n		<li><code>name=&quot;value&quot;</code> <span class=\"required\">required</span><br />\nName of the server variable. See the <a href=\"http://php.net/manual/reserved.variables.php#reserved.variables.server\"><span class=\"caps\">PHP</span> manual</a> for a full list.</li>\n		<li><code>label=&quot;text&quot;</code><br />\nUsed to identify the field in the email. Defaults to the value of the <strong>name</strong> attribute.</li>\n	</ul>\n\n	<h4>Examples</h4>\n\n	<p>Add the IP address of the visitor to the email</p>\n\n<pre><code>&lt;txp:zem_contact_serverinfo name=&quot;REMOTE_ADDR&quot; label=&quot;IP number&quot; /&gt;\n</code></pre>\n\n	<p>Add the name of the visitor&#8217;s browser to the email</p>\n\n<pre><code>&lt;txp:zem_contact_serverinfo name=&quot;HTTP_USER_AGENT&quot; label=&quot;Browser&quot; /&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"zc_send_article\"><code>&lt;txp:zem_contact_send_article /&gt;</code></h3>\n\n	<p>Use this tag in your individual article form, where you want the &#8220;send article&#8221; link to be displayed.</p>\n\n	<h4>Attributes:</h4>\n\n	<ul>\n		<li><code>linktext=&quot;text&quot;</code><br />\nText displayed for the link. Default is <strong>send article</strong></li>\n	</ul>\n\n	<h4>Examples:</h4>\n\n	<p>See <a href=\"#sendarticle\">Getting started</a></p>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h2 id=\"advanced\">Advanced examples</h2>\n\n	<h3 id=\"show_error\">Separate input and error forms</h3>\n\n	<p>Using <code>show_input</code> and <code>show_error</code> to display the form and error messages on different parts of a page. A form is used to make sure the contents of both forms are identical, otherwise they would be seen as two independent forms. The first form only shows errors (no input), the second form only shows the input fields (no errors).</p>\n\n<pre><code>&lt;div id=&quot;error&quot;&gt;\n  &lt;txp:zem_contact form=&quot;contact_form&quot; show_input=&quot;0&quot; /&gt;\n&lt;/div&gt;\n</code>\n<code>&lt;div id=&quot;inputform&quot;&gt;\n  &lt;txp:zem_contact form=&quot;contact_form&quot; show_error=&quot;0&quot; /&gt;\n&lt;/div&gt;\n</code></pre>\n\n	<p>Apart from the <code>show_error</code> and <code>show_input</code> attributes, all other attributes must be 100% identical in both forms, otherwise they would be seen as two unrelated forms.</p>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"subject_form\">User selectable subject field</h3>\n\n	<p>Specify the <code>subject_form</code> attribute and create a form which includes a <code>zem_contact_select</code> tag:</p>\n\n<pre><code>&lt;txp:zem_contact to=&quot;you@example.com&quot; subject_form=&quot;my_subject_form&quot; /&gt;\n  &lt;txp:zem_contact_text label=&quot;Name&quot; /&gt;&lt;br /&gt;\n  &lt;txp:zem_contact_email /&gt;&lt;br /&gt;\n  &lt;txp:zem_contact_select label=&quot;Choose Subject&quot; list=&quot;,Question,Feedback&quot; /&gt;&lt;br /&gt;\n  &lt;txp:zem_contact_textarea label=&quot;Message&quot; /&gt;&lt;br /&gt;\n&lt;/txp:zem_contact&gt;\n</code></pre>\n\n	<p>Create a Textpattern form called &#8220;my_subject_form&#8221;, containing:</p>\n\n<pre><code>&lt;txp:php&gt;\n  global $zem_contact_form;\n  echo $zem_contact_form[&#39;Choose Subject&#39;];\n&lt;/txp:php&gt;\n</code></pre>\n\n	<p>The <code>label</code> used in the <code>zem_contact_select</code> tag must be identical to the corresponding variable in the <code>subject_form</code>. Here we used <code>Choose subject</code>.</p>\n\n	<p>If you&#8217;d prefer to add a common prefix for all subjects, use a <code>subject_form</code> containing:</p>\n\n<pre><code>&lt;txp:php&gt;\n  global $zem_contact_form;\n  echo &#39;My common prefix - &#39; . $zem_contact_form[&#39;Choose Subject&#39;];\n&lt;/txp:php&gt;\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h3 id=\"to_form\">User selectable recipient, without showing email address</h3>\n\n	<p>Specify the <code>to_form</code> attribute and create a form which includes a <code>zem_contact_select</code> tag:</p>\n\n<pre><code>&lt;txp:zem_contact to_form=&quot;my_zem_contact_to_form&quot;&gt;\n  &lt;txp:zem_contact_text label=&quot;Name&quot; /&gt;&lt;br /&gt;\n  &lt;txp:zem_contact_email /&gt;&lt;br /&gt;\n  &lt;txp:zem_contact_select label=&quot;Department&quot; list=&quot;,Support,Sales&quot; /&gt;&lt;br /&gt;\n  &lt;txp:zem_contact_textarea label=&quot;Message&quot; /&gt;&lt;br /&gt;\n&lt;/txp:zem_contact&gt;\n</code></pre>\n\n	<p>Create a Textpattern form called &#8220;my_zem_contact_to_form&#8221;, containing:</p>\n\n<pre><code>&lt;txp:php&gt;\n  global $zem_contact_form;\n  switch($zem_contact_form[&#39;Department&#39;])\n  {\n    case &#39;Support&#39;:\n      echo &#39;crew@example.com&#39;;\n      break;\n    case &#39;Sales&#39;:\n      echo &#39;showmethemoney@example.com&#39;;\n      break;\n    default:\n      echo &#39;someone@example.com&#39;;\n  }\n&lt;/txp:php&gt;\n</code></pre>\n\n	<p>The <code>label</code> used in the <code>zem_contact_select</code> tag must be identical to the corresponsing variable in the <code>to_form</code>. Here we used <code>Department</code>.</p>\n\n	<p>A &#8216;default&#8217; email address in the <code>to_form</code> is specified to ensure that a valid email address is used in cases where you add or change a select/radio option and forget to update the <code>to_form</code>.</p>\n\n	<p class=\"warning\">Never use tags like <code>zem_contact_text</code>, <code>zem_contact_email</code> or <code>zem_contact_textarea</code> for setting the recipient address, otherwise your form can be abused to send spam to any email address!</p>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h2 id=\"styling\">Styling</h2>\n\n	<p>The form itself has a class <strong>zemContactForm</strong> set on the <code>FORM</code> <span class=\"caps\">HTML</span> tag.</p>\n\n	<p>The list of error messages (if any) has a class <strong>zemError</strong> set on the <code>UL</code> <span class=\"caps\">HTML</span> tag that encloses the list of errors.</p>\n\n	<p>All form elements and corresponding labels have the following classes (or ids set):\n	<ol>\n		<li>One of <strong>zemText</strong>, <strong>zemTextarea</strong>, <strong>zemSelect</strong>, <strong>zemRadio</strong>, <strong>zemCheckbox</strong>, <strong>zemSubmit</strong>. It should be obvious which class is used for which form element (and corresponding label).</li>\n		<li><strong>zemRequired</strong> or <strong>errorElement</strong> or <strong>zemRequirederrorElement</strong>, depending on whether the form element is required, an error was found in whatever the visitor entered&#8230; or both.</li>\n		<li>An individual &#8220;id&#8221; or &#8220;class&#8221; set to the value of the <code>name</code> attribute of the corresponding tag. When styling forms based on this class, you should explicitly set the <code>name</code> attribute because automatically generated names may change in newer zem_contact_reborn versions.</li>\n	</ol></p>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h2 id=\"history\">History</h2>\n\n	<p>Only the changes that may affect people who upgrade are detailed below.<br />\nTo save space, links to forum topics that detail all the changes in each version have been added.</p>\n\n	<ul>\n		<li>14 feb 2007: <strong>version 4.0.3.19</strong> <a href=\"http://forum.textpattern.com/viewtopic.php?id=21144\">changelog</a>\n	<ul>\n		<li><a href=\"#sendarticle\">send_article</a> functionality revised, requiring changes when upgrading from earlier versions</li>\n		<li>New language strings: &#8216;send_article&#8217; and &#8216;recipient&#8217; (replaces &#8216;receiver&#8217;)</li>\n		<li>Sets of radio buttons require the new <a href=\"#zc_radio\">group</a> attribute</li>\n		<li>Yes/No values deprecated in favor for the <span class=\"caps\">TXP</span> standard 1/0 values (yes/no still work in this version)</li>\n	</ul></li>\n		<li>20 nov 2006: <strong>version 4.0.3.18</strong> <a href=\"http://forum.textpattern.com/viewtopic.php?id=19823\">changelog</a>\n	<ul>\n		<li>IDs &#8216;zemContactForm&#8217; and &#8216;zemSubmit&#8217; have changed to classes to allow multiple forms per page</li>\n		<li>New language strings: &#8216;form_used&#8217;, &#8216;invalid_utf8&#8217;, &#8216;max_warning&#8217;, &#8216;name&#8217;, &#8216;refresh&#8217;, &#8216;secret&#8217;</li>\n	</ul></li>\n		<li>12 mar 2006: <strong>version 4.0.3.17</strong> <a href=\"http://forum.textpattern.com/viewtopic.php?id=13416\">changelog</a></li>\n		<li>11 feb 2006: <strong>version .16</strong></li>\n		<li>06 feb 2006: <strong>version .15</strong></li>\n		<li>03 feb 2006: <strong>version .14</strong>\n	<ul>\n		<li>Requires separate zem_contact_lang plugin</li>\n	</ul></li>\n		<li>29 jan 2006: <strong>version .12</strong></li>\n		<li>27 jan 2006: <strong>version .11</strong></li>\n		<li>23 jan 2006: <strong>version .09 and .10</strong></li>\n		<li>23 jan 2006: <strong>version .08</strong></li>\n		<li>17 jan 2006: <strong>version .07</strong></li>\n		<li>16 jan 2006: <strong>version .05 and .06</strong></li>\n		<li>15 jan 2006: <strong>version .04</strong></li>\n		<li>10 jan 2006: <strong>version .03</strong></li>\n		<li>19 dec 2005: <strong>version .02</strong></li>\n	</ul>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h2 id=\"credits\">Credits</h2>\n\n	<ul>\n		<li><strong>zem</strong> wrote the zem_contact 0.6 plugin on which this plugin was initially based.</li>\n		<li><strong>Mary</strong> completely revised the plugin code.</li>\n		<li><strong>Stuart</strong> Turned it into a plugin, added a revised help text and additional code. Maintained all plugin versions till 4.0.3.17.</li>\n		<li><strong>wet</strong> added the zem_contact_radio tag.</li>\n		<li><strong>Tranquillo</strong> added the anti-spam <span class=\"caps\">API</span> and zem_contact_send_article functionality.</li>\n		<li><strong>aslsw66</strong>, <strong>jdykast</strong> and others (?) provided additional code</li>\n		<li><strong>Ruud</strong> cleaned up and audited the code to weed out bugs and completely revised the help text. Maintainer of versions 4.0.3.18 and up.</li>\n		<li>Supported and tested to destruction by the Textpattern community.</li>\n	</ul>\n\n	<p><a href=\"#top\">Back to top</a></p>\n\n	<h2 id=\"api\">Zem Contact Reborn&#8217;s <span class=\"caps\">API</span></h2>\n\n	<p>The plugin <span class=\"caps\">API</span> of zem contact, developed by Tranquillo, is similar to the comments <span class=\"caps\">API</span> of Textpattern, which is explained in the Textbook <a href=\"http://textpattern.net/wiki/index.php?title=Plugin_Development_Topics\">Plugin Development Topics</a> and <a href=\"http://textpattern.net/wiki/index.php?title=Combat_Comment_Spam\">Combat Comment Spam</a>.</p>\n\n	<p>Two callback events exist in zem_contact_reborn:\n	<ul>\n		<li><code>zemcontact.submit</code> is called after the form is submitted and the values are checked if empty or valid email addresses, but before the mail is sent.</li>\n		<li><code>zemcontact.form</code> let&#8217;s you insert content in the contact form as displayed to the visitor.</li>\n	</ul></p>\n\n	<p>For reference here are the commands that will be interesting to plugin developers:</p>\n\n<pre><code>// This will call your function before the form is submitted\n// So you can analyse the submitted data\nregister_callback(&#39;abc_myfunction&#39;,&#39;zemcontact.submit&#39;);\n</code>\n<code>// This will call your function and add the output (use return $mystuff)\n// to the contact-form.\nregister_callback(&#39;abc_myotherfunction2&#39;,&#39;zemcontact.form&#39;);\n</code>\n<code>// To get hold of the form-variables you can use\nglobal zem_contact_form;\n</code>\n<code>// With the following two lines you can tell zem_contact if your\n// plugin found spam\n$evaluator =&amp; get_zemcontact_evaluator();\n</code>\n<code>// The passed value must be non-zero to mark the content as spam.\n// Value must be a number between 0 and 1.\n$evaluator -&gt; add_zemcontact_status(1);\n</code></pre>\n\n	<p>Multiple plugins can be active at the same time and each of them can mark the submitted content as spam and prevent the form from being submitted.</p>\n\n	<p><strong>An example of a plug-in connecting to Zem Contact Reborn&#8217;s <span class=\"caps\">API</span>:</strong></p>\n\n<pre><code>register_callback(&#39;pap_zemcontact_form&#39;,&#39;zemcontact.form&#39;);\nregister_callback(&#39;pap_zemcontact_submit&#39;,&#39;zemcontact.submit&#39;);\n</code>\n<code>function pap_zemcontact_form() {\n  $field = &#39;&lt;div style=&quot;display:none&quot;&gt;&#39;.\n    finput(&#39;text&#39;,&#39;phone&#39;,ps(&#39;phone&#39;),&#39;&#39;,&#39;&#39;,&#39;&#39;,&#39;&#39;,&#39;&#39;,&#39;phone&#39;).&#39;&lt;br /&gt;&#39;.\n    finput(&#39;text&#39;,&#39;mail&#39;,ps(&#39;mail&#39;),&#39;&#39;,&#39;&#39;,&#39;&#39;,&#39;&#39;,&#39;&#39;,&#39;mail&#39;).&#39;&lt;/div&gt;&#39;;\n  return $field;&lt;/code&gt;\n}\n</code>\n<code>function pap_zemcontact_submit() {\n  $checking_mail_field = trim(ps(&#39;mail&#39;));\n  $checking_phone_field = trim(ps(&#39;phone&#39;));\n</code>\n<code>  $evaluation =&amp; get_zemcontact_evaluator();\n</code>\n<code>  // If the hidden fields are filled out, the contact form won&#39;t be submitted!\n  if ($checking_mail_field != &#39;&#39; or $checking_phone_field != &#39;&#39;) {\n    $evaluation -&gt; add_zemcontact_status(1);\n  }\n  return;\n}\n</code></pre>\n\n	<p><a href=\"#top\">Back to top</a></p>','\nfunction zem_contact($atts, $thing = \'\')\n{\n	global $sitename, $prefs, $production_status, $zem_contact_from,\n		$zem_contact_recipient, $zem_contact_error, $zem_contact_submit,\n		$zem_contact_form, $zem_contact_labels, $zem_contact_values;\n\n	extract(zem_contact_lAtts(array(\n		\'copysender\'	=> 0,\n		\'form\'		=> \'\',\n		\'from\'		=> \'\',\n		\'from_form\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'contact\'),\n		\'redirect\'	=> \'\',\n		\'show_error\'	=> 1,\n		\'show_input\'	=> 1,\n		\'send_article\'	=> 0,\n		\'subject\'	=> zem_contact_gTxt(\'email_subject\', html_entity_decode($sitename,ENT_QUOTES)),\n		\'subject_form\'	=> \'\',\n		\'to\'		=> \'\',\n		\'to_form\'	=> \'\',\n		\'thanks\'	=> graf(zem_contact_gTxt(\'email_thanks\')),\n		\'thanks_form\'	=> \'\'\n	), $atts));\n\n	unset($atts[\'show_error\'], $atts[\'show_input\']);\n	$zem_contact_form_id = md5(serialize($atts).preg_replace(\'/[\\t\\s\\r\\n]/\',\'\',$thing));\n	$zem_contact_submit = (ps(\'zem_contact_form_id\') == $zem_contact_form_id);\n\n	if (!is_callable(\'mail\'))\n	{\n		return ($production_status == \'live\') ?\n			zem_contact_gTxt(\'mail_sorry\') :\n			gTxt(\'warn_mail_unavailable\');\n	}\n\n	static $headers_sent = false;\n	if (!$headers_sent) {\n		header(\'Last-Modified: \'.gmdate(\'D, d M Y H:i:s\',time()-3600*24*7).\' GMT\');\n		header(\'Expires: \'.gmdate(\'D, d M Y H:i:s\',time()+600).\' GMT\');\n		header(\'Cache-Control: no-cache, must-revalidate\');\n		$headers_sent = true;\n	}\n\n	$nonce   = mysql_real_escape_string(ps(\'zem_contact_nonce\'));\n	$renonce = false;\n\n	if ($zem_contact_submit)\n	{\n		safe_delete(\'txp_discuss_nonce\', \'issue_time < date_sub(now(), interval 10 minute)\');\n		if ($rs = safe_row(\'used\', \'txp_discuss_nonce\', \"nonce = \'$nonce\'\"))\n		{\n			if ($rs[\'used\'])\n			{\n				unset($zem_contact_error);\n				$zem_contact_error[] = zem_contact_gTxt(\'form_used\');\n				$renonce = true;\n				$_POST = array();\n				$_POST[\'zem_contact_submit\'] = TRUE;\n				$_POST[\'zem_contact_form_id\'] = $zem_contact_form_id;\n				$_POST[\'zem_contact_nonce\'] = $nonce;\n			}\n		}\n		else\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'form_expired\');\n			$renonce = true;\n		}\n	}\n\n	if ($zem_contact_submit and $nonce and !$renonce)\n	{\n		$zem_contact_nonce = $nonce;\n	}\n\n	elseif (!$show_error or $show_input)\n	{\n		$zem_contact_nonce = md5(uniqid(rand(), true));\n		safe_insert(\'txp_discuss_nonce\', \"issue_time = now(), nonce = \'$zem_contact_nonce\'\");\n	}\n\n	$form = ($form) ? fetch_form($form) : $thing;\n\n	if (empty($form))\n	{\n		$form = \'\n<txp:zem_contact_text label=\"\'.zem_contact_gTxt(\'name\').\'\" /><br />\n<txp:zem_contact_email /><br />\'.\n($send_article ? \'<txp:zem_contact_email send_article=\"1\" label=\"\'.zem_contact_gTxt(\'recipient\').\'\" /><br />\' : \'\').\n\'<txp:zem_contact_textarea /><br />\n<txp:zem_contact_submit />\n\';\n	}\n\n	$form = parse($form);\n\n	if ($to_form)\n	{\n		$to = parse(fetch_form($to_form));\n	}\n\n	if (!$to and !$send_article)\n	{\n		return zem_contact_gTxt(\'to_missing\');\n	}\n\n	$out = \'\';\n\n	if (!$zem_contact_submit) {\n	  # don\'t show errors or send mail\n	}\n\n	elseif (!empty($zem_contact_error))\n	{\n		if ($show_error or !$show_input)\n		{\n			$out .= n.\'<ul class=\"zemError\">\';\n\n			foreach (array_unique($zem_contact_error) as $error)\n			{\n				$out .= n.t.\'<li>\'.$error.\'</li>\';\n			}\n\n			$out .= n.\'</ul>\';\n\n			if (!$show_input) return $out;\n		}\n	}\n\n	elseif ($show_input and is_array($zem_contact_form))\n	{\n		/// load and check spam plugins/\n		callback_event(\'zemcontact.submit\');\n		$evaluation =& get_zemcontact_evaluator();\n		$clean = $evaluation->get_zemcontact_status();\n		if ($clean != 0) {\n			return zem_contact_gTxt(\'spam\');\n		}\n\n		if ($from_form)\n		{\n			$from = parse(fetch_form($from_form));\n		}\n\n		if ($subject_form)\n		{\n			$subject = parse(fetch_form($subject_form));\n		}\n\n		$sep = !is_windows() ? \"\\n\" : \"\\r\\n\";\n\n		$msg = array();\n\n		foreach ($zem_contact_labels as $name => $label)\n		{\n			if (!trim($zem_contact_values[$name])) continue;\n			$msg[] = $label.\': \'.$zem_contact_values[$name];\n		}\n\n		if ($send_article)\n		{\n			global $thisarticle;\n			$subject = str_replace(\'&#38;\', \'&\', $thisarticle[\'title\']);\n			$msg[] = permlinkurl($thisarticle);\n			$msg[] = $subject;\n			$s_ar = array(\'&#8216;\', \'&#8217;\', \'&#8220;\', \'&#8221;\', \'&#8217;\', \'&#8242;\', \'&#8243;\', \'&#8230;\', \'&#8211;\', \'&#8212;\', \'&#215;\', \'&#8482;\', \'&#174;\', \'&#169;\', \'&lt;\', \'&gt;\', \'&quot;\', \'&amp;\', \'&#38;\', \"\\t\", \'<p\');\n			if ($prefs[\'override_emailcharset\'] and is_callable(\'utf8_decode\')) {\n				$r_ar = array(\"\'\", \"\'\", \'\"\', \'\"\', \"\'\", \"\'\", \'\"\', \'...\', \'-\', \'--\', \'x\', \'[tm]\', \'(r)\', \'(c)\', \'<\', \'>\', \'\"\', \'&\', \'&\', \' \', \"\\n<p\");\n			}\n			else\n			{\n				$r_ar = array(\'‘\', \'’\', \'“\', \'”\', \'’\', \'′\', \'″\', \'…\', \'–\', \'—\', \'×\', \'™\', \'®\', \'©\', \'<\', \'>\', \'\"\', \'&\', \'&\', \' \', \"\\n<p\");\n			}\n			$msg[] = trim(strip_tags(str_replace($s_ar,$r_ar,(trim(strip_tags($thisarticle[\'excerpt\'])) ? $thisarticle[\'excerpt\'] : $thisarticle[\'body\']))));\n			if (empty($zem_contact_recipient))\n			{\n				return zem_contact_gTxt(\'field_missing\', zem_contact_gTxt(\'recipient\'));\n			}\n			else\n			{\n				$to = $zem_contact_recipient;\n			}\n		}\n\n		$msg = join(\"\\n\\n\", $msg);\n		$msg = str_replace(\"\\r\\n\", \"\\n\", $msg);\n		$msg = str_replace(\"\\r\", \"\\n\", $msg);\n		$msg = str_replace(\"\\n\", $sep, $msg);\n\n		if ($from)\n		{\n			$reply = $zem_contact_from;\n		}\n\n		else\n		{\n			$from = $zem_contact_from;\n			$reply = \'\';\n		}\n\n		$from    = zem_contact_strip($from);\n		$to      = zem_contact_strip($to);\n		$subject = zem_contact_strip($subject);\n		$reply   = zem_contact_strip($reply);\n		$msg     = zem_contact_strip($msg, FALSE);\n\n		if ($prefs[\'override_emailcharset\'] and is_callable(\'utf8_decode\'))\n		{\n			$charset = \'ISO-8859-1\';\n			$subject = utf8_decode($subject);\n			$msg     = utf8_decode($msg);\n		}\n\n		else\n		{\n			$charset = \'UTF-8\';\n		}\n\n		$subject = zem_contact_mailheader($subject, \'text\');\n\n		$headers = \'From: \'.$from.\n			($reply ? ($sep.\'Reply-To: \'.$reply) : \'\').\n			$sep.\'X-Mailer: Textpattern (zem_contact_reborn)\'.\n			$sep.\'X-Originating-IP: \'.zem_contact_strip((!empty($_SERVER[\'HTTP_X_FORWARDED_FOR\']) ? $_SERVER[\'HTTP_X_FORWARDED_FOR\'].\' via \' : \'\').$_SERVER[\'REMOTE_ADDR\']).\n			$sep.\'Content-Transfer-Encoding: 8bit\'.\n			$sep.\'Content-Type: text/plain; charset=\"\'.$charset.\'\"\';\n\n		safe_update(\'txp_discuss_nonce\', \"used = \'1\', issue_time = now()\", \"nonce = \'$nonce\'\");\n\n		if (mail($to, $subject, $msg, $headers))\n		{\n			$_POST = array();\n\n			if ($copysender and $zem_contact_from)\n			{\n				mail(zem_contact_strip($zem_contact_from), $subject, $msg, $headers);\n			}\n\n			if ($redirect)\n			{\n				while (@ob_end_clean());\n				$uri = hu.ltrim($redirect,\'/\');\n				if (empty($_SERVER[\'FCGI_ROLE\']) and empty($_ENV[\'FCGI_ROLE\']))\n				{\n					txp_status_header(\'303 See Other\');\n					header(\'Location: \'.$uri);\n					header(\'Connection: close\');\n					header(\'Content-Length: 0\');\n				}\n				else\n				{\n					$uri = htmlspecialchars($uri);\n					$refresh = zem_contact_gTxt(\'refresh\');\n					echo <<<END\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n	<title>$sitename</title>\n	<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n	<meta http-equiv=\"refresh\" content=\"0;url=$uri\" />\n</head>\n<body>\n<a href=\"$uri\">$refresh</a>\n</body>\n</html>\nEND;\n				}\n				exit;\n			}\n\n			else\n			{\n				return \'<div class=\"zemThanks\" id=\"zcr\'.$zem_contact_form_id.\'\">\' .\n					($thanks_form ? fetch_form($thanks_form) : $thanks) .\n					\'</div>\';\n			}\n		}\n\n		else\n		{\n			$out .= graf(zem_contact_gTxt(\'mail_sorry\'));\n		}\n	}\n\n	if ($show_input and !$send_article or gps(\'zem_contact_send_article\'))\n	{\n		return \'<form method=\"post\"\'.((!$show_error and $zem_contact_error) ? \'\' : \' id=\"zcr\'.$zem_contact_form_id.\'\"\').\' class=\"zemContactForm\" action=\"\'.htmlspecialchars(serverSet(\'REQUEST_URI\')).\'#zcr\'.$zem_contact_form_id.\'\">\'.\n			( $label ? n.\'<fieldset>\' : n.\'<div>\' ).\n			( $label ? n.\'<legend>\'.htmlspecialchars($label).\'</legend>\' : \'\' ).\n			$out.\n			n.\'<input type=\"hidden\" name=\"zem_contact_nonce\" value=\"\'.$zem_contact_nonce.\'\" />\'.\n			n.\'<input type=\"hidden\" name=\"zem_contact_form_id\" value=\"\'.$zem_contact_form_id.\'\" />\'.\n			$form.\n			callback_event(\'zemcontact.form\').\n			( $label ? (n.\'</fieldset>\') : (n.\'</div>\') ).\n			n.\'</form>\';\n	}\n\n	return \'\';\n}\n\nfunction zem_contact_strip($str, $header = TRUE) {\n	if ($header) $str = strip_rn($str);\n	return preg_replace(\'/[\\x00]/\', \' \', $str);\n}\n\nfunction zem_contact_text($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> br,\n		\'default\'	=> \'\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'text\'),\n		\'max\'		=> 100,\n		\'min\'		=> 0,\n		\'name\'		=> \'\',\n		\'required\'	=> 1,\n		\'size\'		=> \'\'\n	), $atts));\n\n	$min = intval($min);\n	$max = intval($max);\n	$size = intval($size);\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if ($zem_contact_submit)\n	{\n		$value = trim(ps($name));\n		$utf8len = preg_match_all(\"/./su\", $value, $utf8ar);\n		$hlabel = htmlspecialchars($label);\n\n		if (strlen($value))\n		{\n			if (!$utf8len)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_utf8\', $hlabel);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($min and $utf8len < $min)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'min_warning\', $hlabel, $min);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($max and $utf8len > $max)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'max_warning\', $hlabel, $max);\n				$isError = \"errorElement\";\n				#$value = join(\'\',array_slice($ar[0],0,$max));\n			}\n\n			else\n			{\n				zem_contact_store($name, $label, $value);\n			}\n		}\n		elseif ($required)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', $hlabel);\n			$isError = \"errorElement\";\n		}\n	}\n\n	else\n	{\n		$value = $default;\n	}\n\n	$size = ($size) ? \' size=\"\'.$size.\'\"\' : \'\';\n	$maxlength = ($max) ? \' maxlength=\"\'.$max.\'\"\' : \'\';\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n        return \'<label for=\"\'.$name.\'\" class=\"zemText \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\'.$break.\n		\'<input type=\"text\" id=\"\'.$name.\'\" class=\"zemText \'.$zemRequired.$isError.\'\" name=\"\'.$name.\'\" value=\"\'.htmlspecialchars($value).\'\"\'.$size.$maxlength.\' />\';\n}\n\nfunction zem_contact_textarea($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> br,\n		\'cols\'		=> 58,\n		\'default\'	=> \'\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'message\'),\n		\'max\'		=> 10000,\n		\'min\'		=> 0,\n		\'name\'		=> \'\',\n		\'required\'	=> 1,\n		\'rows\'		=> 8\n	), $atts));\n\n	$min = intval($min);\n	$max = intval($max);\n	$cols = intval($cols);\n	$rows = intval($rows);\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if ($zem_contact_submit)\n	{\n		$value = preg_replace(\'/^\\s*[\\r\\n]/\', \'\', rtrim(ps($name)));\n		$utf8len = preg_match_all(\"/./su\", ltrim($value), $utf8ar);\n		$hlabel = htmlspecialchars($label);\n\n		if (strlen(ltrim($value)))\n		{\n			if (!$utf8len)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_utf8\', $hlabel);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($min and $utf8len < $min)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'min_warning\', $hlabel, $min);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($max and $utf8len > $max)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'max_warning\', $hlabel, $max);\n				$isError = \"errorElement\";\n				#$value = join(\'\',array_slice($utf8ar[0],0,$max));\n			}\n\n			else\n			{\n				zem_contact_store($name, $label, $value);\n			}\n		}\n\n		elseif ($required)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', $hlabel);\n			$isError = \"errorElement\";\n		}\n	}\n\n	else\n	{\n		$value = $default;\n	}\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n	return \'<label for=\"\'.$name.\'\" class=\"zemTextarea \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\'.$break.\n		\'<textarea id=\"\'.$name.\'\" class=\"zemTextarea \'.$zemRequired.$isError.\'\" name=\"\'.$name.\'\" cols=\"\'.$cols.\'\" rows=\"\'.$rows.\'\">\'.htmlspecialchars($value).\'</textarea>\';\n}\n\nfunction zem_contact_email($atts)\n{\n	global $zem_contact_error, $zem_contact_submit, $zem_contact_from, $zem_contact_recipient;\n\n	extract(zem_contact_lAtts(array(\n		\'default\'	=> \'\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'email\'),\n		\'max\'		=> 100,\n		\'min\'		=> 0,\n		\'name\'		=> \'\',\n		\'required\'	=> 1,\n		\'break\'		=> br,\n		\'size\'		=> \'\',\n		\'send_article\'	=> 0\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	$email = $zem_contact_submit ? trim(ps($name)) : $default;\n\n	if ($zem_contact_submit and strlen($email))\n	{\n		if (!is_valid_email($email))\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'invalid_email\', htmlspecialchars($email));\n			$isError = \"errorElement\";\n		}\n\n		else\n		{\n			preg_match(\"/@(.+)$/\", $email, $match);\n			$domain = $match[1];\n\n			if (is_callable(\'checkdnsrr\') and checkdnsrr(\'textpattern.com.\',\'A\') and !checkdnsrr($domain.\'.\',\'MX\') and !checkdnsrr($domain.\'.\',\'A\'))\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_host\', htmlspecialchars($domain));\n				$isError = \"errorElement\";\n			}\n\n			else\n			{\n				if ($send_article) {\n					$zem_contact_recipient = $email;\n				}\n				else {\n					$zem_contact_from = $email;\n				}\n			}\n		}\n	}\n\n	return zem_contact_text(array(\n		\'default\'	=> $email,\n		\'isError\'	=> $isError,\n		\'label\'		=> $label,\n		\'max\'		=> $max,\n		\'min\'		=> $min,\n		\'name\'		=> $name,\n		\'required\'	=> $required,\n		\'break\'		=> $break,\n		\'size\'		=> $size\n	));\n}\n\nfunction zem_contact_select($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'name\'		=> \'\',\n		\'break\'		=> \' \',\n		\'delimiter\'	=> \',\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'option\'),\n		\'list\'		=> zem_contact_gTxt(\'general_inquiry\'),\n		\'required\'	=> 1,\n		\'selected\'	=> \'\'\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	$list = array_map(\'trim\', split($delimiter, preg_replace(\'/[\\r\\n\\t\\s]+/\', \' \',$list)));\n\n	if ($zem_contact_submit)\n	{\n		$value = trim(ps($name));\n\n		if (strlen($value))\n		{\n			if (in_array($value, $list))\n			{\n				zem_contact_store($name, $label, $value);\n			}\n\n			else\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_value\', htmlspecialchars($label), htmlspecialchars($value));\n				$isError = \"errorElement\";\n			}\n		}\n\n		elseif ($required)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', htmlspecialchars($label));\n			$isError = \"errorElement\";\n		}\n	}\n	else\n	{\n		$value = $selected;\n	}\n\n	$out = \'\';\n\n	foreach ($list as $item)\n	{\n		$out .= n.t.\'<option\'.($item == $value ? \' selected=\"selected\">\' : \'>\').(strlen($item) ? htmlspecialchars($item) : \' \').\'</option>\';\n	}\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n	return \'<label for=\"\'.$name.\'\" class=\"zemSelect \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\'.$break.\n		n.\'<select id=\"\'.$name.\'\" name=\"\'.$name.\'\" class=\"zemSelect \'.$zemRequired.$isError.\'\">\'.\n			$out.\n		n.\'</select>\';\n}\n\nfunction zem_contact_checkbox($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> \' \',\n		\'checked\'	=> 0,\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'checkbox\'),\n		\'name\'		=> \'\',\n		\'required\'	=> 1\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if ($zem_contact_submit)\n	{\n		$value = (bool) ps($name);\n\n		if ($required and !$value)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', htmlspecialchars($label));\n			$isError = \"errorElement\";\n		}\n\n		else\n		{\n			zem_contact_store($name, $label, $value ? gTxt(\'yes\') : gTxt(\'no\'));\n		}\n	}\n\n	else {\n		$value = $checked;\n	}\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n	return \'<input type=\"checkbox\" id=\"\'.$name.\'\" class=\"zemCheckbox \'.$zemRequired.$isError.\'\" name=\"\'.$name.\'\"\'.\n		($value ? \' checked=\"checked\"\' : \'\').\' />\'.$break.\n		\'<label for=\"\'.$name.\'\" class=\"zemCheckbox \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\';\n}\n\nfunction zem_contact_serverinfo($atts)\n{\n	global $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'label\'		=> \'\',\n		\'name\'		=> \'\'\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if (strlen($name) and $zem_contact_submit)\n	{\n		if (!$label) $label = $name;\n		zem_contact_store($name, $label, serverSet($name));\n	}\n}\n\nfunction zem_contact_secret($atts, $thing = \'\')\n{\n	global $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'name\'	=> \'\',\n		\'label\'	=> zem_contact_gTxt(\'secret\'),\n		\'value\'	=> \'\'\n	), $atts));\n\n	$name = zem_contact_label2name($name ? $name : $label);\n\n	if ($zem_contact_submit)\n	{\n		if ($thing) $value = trim(parse($thing));\n		zem_contact_store($name, $label, $value);\n	}\n\n	return \'\';\n}\n\nfunction zem_contact_radio($atts)\n{\n	global $zem_contact_error, $zem_contact_submit, $zem_contact_values;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> \' \',\n		\'checked\'	=> 0,\n		\'group\'		=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'option\'),\n		\'name\'		=> \'\'\n	), $atts));\n\n	static $cur_name = \'\';\n	static $cur_group = \'\';\n\n	if (!$name and !$group and !$cur_name and !$cur_group) {\n		$cur_group = zem_contact_gTxt(\'radio\');\n		$cur_name = $cur_group;\n	}\n	if ($group and !$name and $group != $cur_group) $name = $group;\n\n	if ($name) $cur_name = $name;\n	else $name = $cur_name;\n\n	if ($group) $cur_group = $group;\n	else $group = $cur_group;\n\n	$id   = \'q\'.md5($name.\'=>\'.$label);\n	$name = zem_contact_label2name($name);\n\n	if ($zem_contact_submit)\n	{\n		$is_checked = (ps($name) == $id);\n\n		if ($is_checked or $checked and !isset($zem_contact_values[$name]))\n		{\n			zem_contact_store($name, $group, $label);\n		}\n	}\n\n	else\n	{\n		$is_checked = $checked;\n	}\n\n	return \'<input value=\"\'.$id.\'\" type=\"radio\" id=\"\'.$id.\'\" class=\"zemRadio \'.$name.\'\" name=\"\'.$name.\'\"\'.\n		( $is_checked ? \' checked=\"checked\" />\' : \' />\').$break.\n		\'<label for=\"\'.$id.\'\" class=\"zemRadio \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\';\n}\n\nfunction zem_contact_send_article($atts)\n{\n	if (!isset($_REQUEST[\'zem_contact_send_article\'])) {\n		$linktext = (empty($atts[\'linktext\'])) ? zem_contact_gTxt(\'send_article\') : $atts[\'linktext\'];\n		$join = (empty($_SERVER[\'QUERY_STRING\'])) ? \'?\' : \'&\';\n		$href = $_SERVER[\'REQUEST_URI\'].$join.\'zem_contact_send_article=yes\';\n		return \'<a href=\"\'.htmlspecialchars($href).\'\">\'.htmlspecialchars($linktext).\'</a>\';\n	}\n	return;\n}\n\nfunction zem_contact_submit($atts, $thing)\n{\n	extract(zem_contact_lAtts(array(\n		\'button\'	=> 0,\n		\'label\'		=> zem_contact_gTxt(\'send\')\n	), $atts));\n\n	$label = htmlspecialchars($label);\n\n	if ($button or strlen($thing))\n	{\n		return \'<button type=\"submit\" class=\"zemSubmit\" name=\"zem_contact_submit\" value=\"\'.$label.\'\">\'.($thing ? trim(parse($thing)) : $label).\'</button>\';\n	}\n	else\n	{\n		return \'<input type=\"submit\" class=\"zemSubmit\" name=\"zem_contact_submit\" value=\"\'.$label.\'\" />\';\n	}\n}\n\nfunction zem_contact_lAtts($arr, $atts)\n{\n	foreach(array(\'button\', \'copysender\', \'checked\', \'required\', \'send_article\', \'show_input\', \'show_error\') as $key)\n	{\n		if (isset($atts[$key]))\n		{\n			$atts[$key] = ($atts[$key] === \'yes\' or intval($atts[$key])) ? 1 : 0;\n		}\n	}\n	if (isset($atts[\'break\']) and $atts[\'break\'] == \'br\') $atts[\'break\'] = \'<br />\';\n	return lAtts($arr, $atts);\n}\n\nclass zemcontact_evaluation\n{\n	var $status;\n\n	function zemcontact_evaluation() {\n		$this->status = 0;\n	}\n\n	function add_zemcontact_status($check) {\n		$this->status += $check;\n	}\n\n	function get_zemcontact_status() {\n		return $this->status;\n	}\n}\n\nfunction &get_zemcontact_evaluator()\n{\n	static $instance;\n\n	if(!isset($instance)) {\n		$instance = new zemcontact_evaluation();\n	}\n	return $instance;\n}\n\nfunction zem_contact_label2name($label)\n{\n	$label = trim($label);\n	if (strlen($label) == 0) return \'invalid\';\n	if (strlen($label) <= 32 and preg_match(\'/^[a-zA-Z][A-Za-z0-9:_-]*$/\', $label)) return $label;\n	else return \'q\'.md5($label);\n}\n\nfunction zem_contact_store($name, $label, $value)\n{\n	global $zem_contact_form, $zem_contact_labels, $zem_contact_values;\n	$zem_contact_form[$label] = $value;\n	$zem_contact_labels[$name] = $label;\n	$zem_contact_values[$name] = $value;\n}\n\nfunction zem_contact_mailheader($string, $type)\n{\n	global $prefs;\n	if (!strstr($string,\'=?\') and !preg_match(\'/[\\x00-\\x1F\\x7F-\\xFF]/\', $string)) {\n		if (\"phrase\" == $type) {\n			if (preg_match(\'/[][()<>@,;:\".\\x5C]/\', $string)) {\n				$string = \'\"\'. strtr($string, array(\"\\\\\" => \"\\\\\\\\\", \'\"\' => \'\\\"\')) . \'\"\';\n			}\n		}\n		elseif (\"text\" != $type) {\n			trigger_error(\'Unknown encode_mailheader type\', E_USER_WARNING);\n		}\n		return $string;\n	}\n	if ($prefs[\'override_emailcharset\']) {\n		$start = \'=?ISO-8859-1?B?\';\n		$pcre  = \'/.{1,42}/s\';\n	}\n	else {\n		$start = \'=?UTF-8?B?\';\n		$pcre  = \'/.{1,45}(?=[\\x00-\\x7F\\xC0-\\xFF]|$)/s\';\n	}\n	$end = \'?=\';\n	$sep = is_windows() ? \"\\r\\n\" : \"\\n\";\n	preg_match_all($pcre, $string, $matches);\n	return $start . join($end.$sep.\' \'.$start, array_map(\'base64_encode\',$matches[0])) . $end;\n}\n','\nfunction zem_contact($atts, $thing = \'\')\n{\n	global $sitename, $prefs, $production_status, $zem_contact_from,\n		$zem_contact_recipient, $zem_contact_error, $zem_contact_submit,\n		$zem_contact_form, $zem_contact_labels, $zem_contact_values;\n\n	extract(zem_contact_lAtts(array(\n		\'copysender\'	=> 0,\n		\'form\'		=> \'\',\n		\'from\'		=> \'\',\n		\'from_form\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'contact\'),\n		\'redirect\'	=> \'\',\n		\'show_error\'	=> 1,\n		\'show_input\'	=> 1,\n		\'send_article\'	=> 0,\n		\'subject\'	=> zem_contact_gTxt(\'email_subject\', html_entity_decode($sitename,ENT_QUOTES)),\n		\'subject_form\'	=> \'\',\n		\'to\'		=> \'\',\n		\'to_form\'	=> \'\',\n		\'thanks\'	=> graf(zem_contact_gTxt(\'email_thanks\')),\n		\'thanks_form\'	=> \'\'\n	), $atts));\n\n	unset($atts[\'show_error\'], $atts[\'show_input\']);\n	$zem_contact_form_id = md5(serialize($atts).preg_replace(\'/[\\t\\s\\r\\n]/\',\'\',$thing));\n	$zem_contact_submit = (ps(\'zem_contact_form_id\') == $zem_contact_form_id);\n\n	if (!is_callable(\'mail\'))\n	{\n		return ($production_status == \'live\') ?\n			zem_contact_gTxt(\'mail_sorry\') :\n			gTxt(\'warn_mail_unavailable\');\n	}\n\n	static $headers_sent = false;\n	if (!$headers_sent) {\n		header(\'Last-Modified: \'.gmdate(\'D, d M Y H:i:s\',time()-3600*24*7).\' GMT\');\n		header(\'Expires: \'.gmdate(\'D, d M Y H:i:s\',time()+600).\' GMT\');\n		header(\'Cache-Control: no-cache, must-revalidate\');\n		$headers_sent = true;\n	}\n\n	$nonce   = mysql_real_escape_string(ps(\'zem_contact_nonce\'));\n	$renonce = false;\n\n	if ($zem_contact_submit)\n	{\n		safe_delete(\'txp_discuss_nonce\', \'issue_time < date_sub(now(), interval 10 minute)\');\n		if ($rs = safe_row(\'used\', \'txp_discuss_nonce\', \"nonce = \'$nonce\'\"))\n		{\n			if ($rs[\'used\'])\n			{\n				unset($zem_contact_error);\n				$zem_contact_error[] = zem_contact_gTxt(\'form_used\');\n				$renonce = true;\n				$_POST = array();\n				$_POST[\'zem_contact_submit\'] = TRUE;\n				$_POST[\'zem_contact_form_id\'] = $zem_contact_form_id;\n				$_POST[\'zem_contact_nonce\'] = $nonce;\n			}\n		}\n		else\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'form_expired\');\n			$renonce = true;\n		}\n	}\n\n	if ($zem_contact_submit and $nonce and !$renonce)\n	{\n		$zem_contact_nonce = $nonce;\n	}\n\n	elseif (!$show_error or $show_input)\n	{\n		$zem_contact_nonce = md5(uniqid(rand(), true));\n		safe_insert(\'txp_discuss_nonce\', \"issue_time = now(), nonce = \'$zem_contact_nonce\'\");\n	}\n\n	$form = ($form) ? fetch_form($form) : $thing;\n\n	if (empty($form))\n	{\n		$form = \'\n<txp:zem_contact_text label=\"\'.zem_contact_gTxt(\'name\').\'\" /><br />\n<txp:zem_contact_email /><br />\'.\n($send_article ? \'<txp:zem_contact_email send_article=\"1\" label=\"\'.zem_contact_gTxt(\'recipient\').\'\" /><br />\' : \'\').\n\'<txp:zem_contact_textarea /><br />\n<txp:zem_contact_submit />\n\';\n	}\n\n	$form = parse($form);\n\n	if ($to_form)\n	{\n		$to = parse(fetch_form($to_form));\n	}\n\n	if (!$to and !$send_article)\n	{\n		return zem_contact_gTxt(\'to_missing\');\n	}\n\n	$out = \'\';\n\n	if (!$zem_contact_submit) {\n	  # don\'t show errors or send mail\n	}\n\n	elseif (!empty($zem_contact_error))\n	{\n		if ($show_error or !$show_input)\n		{\n			$out .= n.\'<ul class=\"zemError\">\';\n\n			foreach (array_unique($zem_contact_error) as $error)\n			{\n				$out .= n.t.\'<li>\'.$error.\'</li>\';\n			}\n\n			$out .= n.\'</ul>\';\n\n			if (!$show_input) return $out;\n		}\n	}\n\n	elseif ($show_input and is_array($zem_contact_form))\n	{\n		/// load and check spam plugins/\n		callback_event(\'zemcontact.submit\');\n		$evaluation =& get_zemcontact_evaluator();\n		$clean = $evaluation->get_zemcontact_status();\n		if ($clean != 0) {\n			return zem_contact_gTxt(\'spam\');\n		}\n\n		if ($from_form)\n		{\n			$from = parse(fetch_form($from_form));\n		}\n\n		if ($subject_form)\n		{\n			$subject = parse(fetch_form($subject_form));\n		}\n\n		$sep = !is_windows() ? \"\\n\" : \"\\r\\n\";\n\n		$msg = array();\n\n		foreach ($zem_contact_labels as $name => $label)\n		{\n			if (!trim($zem_contact_values[$name])) continue;\n			$msg[] = $label.\': \'.$zem_contact_values[$name];\n		}\n\n		if ($send_article)\n		{\n			global $thisarticle;\n			$subject = str_replace(\'&#38;\', \'&\', $thisarticle[\'title\']);\n			$msg[] = permlinkurl($thisarticle);\n			$msg[] = $subject;\n			$s_ar = array(\'&#8216;\', \'&#8217;\', \'&#8220;\', \'&#8221;\', \'&#8217;\', \'&#8242;\', \'&#8243;\', \'&#8230;\', \'&#8211;\', \'&#8212;\', \'&#215;\', \'&#8482;\', \'&#174;\', \'&#169;\', \'&lt;\', \'&gt;\', \'&quot;\', \'&amp;\', \'&#38;\', \"\\t\", \'<p\');\n			if ($prefs[\'override_emailcharset\'] and is_callable(\'utf8_decode\')) {\n				$r_ar = array(\"\'\", \"\'\", \'\"\', \'\"\', \"\'\", \"\'\", \'\"\', \'...\', \'-\', \'--\', \'x\', \'[tm]\', \'(r)\', \'(c)\', \'<\', \'>\', \'\"\', \'&\', \'&\', \' \', \"\\n<p\");\n			}\n			else\n			{\n				$r_ar = array(\'‘\', \'’\', \'“\', \'”\', \'’\', \'′\', \'″\', \'…\', \'–\', \'—\', \'×\', \'™\', \'®\', \'©\', \'<\', \'>\', \'\"\', \'&\', \'&\', \' \', \"\\n<p\");\n			}\n			$msg[] = trim(strip_tags(str_replace($s_ar,$r_ar,(trim(strip_tags($thisarticle[\'excerpt\'])) ? $thisarticle[\'excerpt\'] : $thisarticle[\'body\']))));\n			if (empty($zem_contact_recipient))\n			{\n				return zem_contact_gTxt(\'field_missing\', zem_contact_gTxt(\'recipient\'));\n			}\n			else\n			{\n				$to = $zem_contact_recipient;\n			}\n		}\n\n		$msg = join(\"\\n\\n\", $msg);\n		$msg = str_replace(\"\\r\\n\", \"\\n\", $msg);\n		$msg = str_replace(\"\\r\", \"\\n\", $msg);\n		$msg = str_replace(\"\\n\", $sep, $msg);\n\n		if ($from)\n		{\n			$reply = $zem_contact_from;\n		}\n\n		else\n		{\n			$from = $zem_contact_from;\n			$reply = \'\';\n		}\n\n		$from    = zem_contact_strip($from);\n		$to      = zem_contact_strip($to);\n		$subject = zem_contact_strip($subject);\n		$reply   = zem_contact_strip($reply);\n		$msg     = zem_contact_strip($msg, FALSE);\n\n		if ($prefs[\'override_emailcharset\'] and is_callable(\'utf8_decode\'))\n		{\n			$charset = \'ISO-8859-1\';\n			$subject = utf8_decode($subject);\n			$msg     = utf8_decode($msg);\n		}\n\n		else\n		{\n			$charset = \'UTF-8\';\n		}\n\n		$subject = zem_contact_mailheader($subject, \'text\');\n\n		$headers = \'From: \'.$from.\n			($reply ? ($sep.\'Reply-To: \'.$reply) : \'\').\n			$sep.\'X-Mailer: Textpattern (zem_contact_reborn)\'.\n			$sep.\'X-Originating-IP: \'.zem_contact_strip((!empty($_SERVER[\'HTTP_X_FORWARDED_FOR\']) ? $_SERVER[\'HTTP_X_FORWARDED_FOR\'].\' via \' : \'\').$_SERVER[\'REMOTE_ADDR\']).\n			$sep.\'Content-Transfer-Encoding: 8bit\'.\n			$sep.\'Content-Type: text/plain; charset=\"\'.$charset.\'\"\';\n\n		safe_update(\'txp_discuss_nonce\', \"used = \'1\', issue_time = now()\", \"nonce = \'$nonce\'\");\n\n		if (mail($to, $subject, $msg, $headers))\n		{\n			$_POST = array();\n\n			if ($copysender and $zem_contact_from)\n			{\n				mail(zem_contact_strip($zem_contact_from), $subject, $msg, $headers);\n			}\n\n			if ($redirect)\n			{\n				while (@ob_end_clean());\n				$uri = hu.ltrim($redirect,\'/\');\n				if (empty($_SERVER[\'FCGI_ROLE\']) and empty($_ENV[\'FCGI_ROLE\']))\n				{\n					txp_status_header(\'303 See Other\');\n					header(\'Location: \'.$uri);\n					header(\'Connection: close\');\n					header(\'Content-Length: 0\');\n				}\n				else\n				{\n					$uri = htmlspecialchars($uri);\n					$refresh = zem_contact_gTxt(\'refresh\');\n					echo <<<END\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n	<title>$sitename</title>\n	<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n	<meta http-equiv=\"refresh\" content=\"0;url=$uri\" />\n</head>\n<body>\n<a href=\"$uri\">$refresh</a>\n</body>\n</html>\nEND;\n				}\n				exit;\n			}\n\n			else\n			{\n				return \'<div class=\"zemThanks\" id=\"zcr\'.$zem_contact_form_id.\'\">\' .\n					($thanks_form ? fetch_form($thanks_form) : $thanks) .\n					\'</div>\';\n			}\n		}\n\n		else\n		{\n			$out .= graf(zem_contact_gTxt(\'mail_sorry\'));\n		}\n	}\n\n	if ($show_input and !$send_article or gps(\'zem_contact_send_article\'))\n	{\n		return \'<form method=\"post\"\'.((!$show_error and $zem_contact_error) ? \'\' : \' id=\"zcr\'.$zem_contact_form_id.\'\"\').\' class=\"zemContactForm\" action=\"\'.htmlspecialchars(serverSet(\'REQUEST_URI\')).\'#zcr\'.$zem_contact_form_id.\'\">\'.\n			( $label ? n.\'<fieldset>\' : n.\'<div>\' ).\n			( $label ? n.\'<legend>\'.htmlspecialchars($label).\'</legend>\' : \'\' ).\n			$out.\n			n.\'<input type=\"hidden\" name=\"zem_contact_nonce\" value=\"\'.$zem_contact_nonce.\'\" />\'.\n			n.\'<input type=\"hidden\" name=\"zem_contact_form_id\" value=\"\'.$zem_contact_form_id.\'\" />\'.\n			$form.\n			callback_event(\'zemcontact.form\').\n			( $label ? (n.\'</fieldset>\') : (n.\'</div>\') ).\n			n.\'</form>\';\n	}\n\n	return \'\';\n}\n\nfunction zem_contact_strip($str, $header = TRUE) {\n	if ($header) $str = strip_rn($str);\n	return preg_replace(\'/[\\x00]/\', \' \', $str);\n}\n\nfunction zem_contact_text($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> br,\n		\'default\'	=> \'\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'text\'),\n		\'max\'		=> 100,\n		\'min\'		=> 0,\n		\'name\'		=> \'\',\n		\'required\'	=> 1,\n		\'size\'		=> \'\'\n	), $atts));\n\n	$min = intval($min);\n	$max = intval($max);\n	$size = intval($size);\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if ($zem_contact_submit)\n	{\n		$value = trim(ps($name));\n		$utf8len = preg_match_all(\"/./su\", $value, $utf8ar);\n		$hlabel = htmlspecialchars($label);\n\n		if (strlen($value))\n		{\n			if (!$utf8len)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_utf8\', $hlabel);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($min and $utf8len < $min)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'min_warning\', $hlabel, $min);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($max and $utf8len > $max)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'max_warning\', $hlabel, $max);\n				$isError = \"errorElement\";\n				#$value = join(\'\',array_slice($ar[0],0,$max));\n			}\n\n			else\n			{\n				zem_contact_store($name, $label, $value);\n			}\n		}\n		elseif ($required)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', $hlabel);\n			$isError = \"errorElement\";\n		}\n	}\n\n	else\n	{\n		$value = $default;\n	}\n\n	$size = ($size) ? \' size=\"\'.$size.\'\"\' : \'\';\n	$maxlength = ($max) ? \' maxlength=\"\'.$max.\'\"\' : \'\';\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n        return \'<label for=\"\'.$name.\'\" class=\"zemText \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\'.$break.\n		\'<input type=\"text\" id=\"\'.$name.\'\" class=\"zemText \'.$zemRequired.$isError.\'\" name=\"\'.$name.\'\" value=\"\'.htmlspecialchars($value).\'\"\'.$size.$maxlength.\' />\';\n}\n\nfunction zem_contact_textarea($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> br,\n		\'cols\'		=> 58,\n		\'default\'	=> \'\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'message\'),\n		\'max\'		=> 10000,\n		\'min\'		=> 0,\n		\'name\'		=> \'\',\n		\'required\'	=> 1,\n		\'rows\'		=> 8\n	), $atts));\n\n	$min = intval($min);\n	$max = intval($max);\n	$cols = intval($cols);\n	$rows = intval($rows);\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if ($zem_contact_submit)\n	{\n		$value = preg_replace(\'/^\\s*[\\r\\n]/\', \'\', rtrim(ps($name)));\n		$utf8len = preg_match_all(\"/./su\", ltrim($value), $utf8ar);\n		$hlabel = htmlspecialchars($label);\n\n		if (strlen(ltrim($value)))\n		{\n			if (!$utf8len)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_utf8\', $hlabel);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($min and $utf8len < $min)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'min_warning\', $hlabel, $min);\n				$isError = \"errorElement\";\n			}\n\n			elseif ($max and $utf8len > $max)\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'max_warning\', $hlabel, $max);\n				$isError = \"errorElement\";\n				#$value = join(\'\',array_slice($utf8ar[0],0,$max));\n			}\n\n			else\n			{\n				zem_contact_store($name, $label, $value);\n			}\n		}\n\n		elseif ($required)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', $hlabel);\n			$isError = \"errorElement\";\n		}\n	}\n\n	else\n	{\n		$value = $default;\n	}\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n	return \'<label for=\"\'.$name.\'\" class=\"zemTextarea \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\'.$break.\n		\'<textarea id=\"\'.$name.\'\" class=\"zemTextarea \'.$zemRequired.$isError.\'\" name=\"\'.$name.\'\" cols=\"\'.$cols.\'\" rows=\"\'.$rows.\'\">\'.htmlspecialchars($value).\'</textarea>\';\n}\n\nfunction zem_contact_email($atts)\n{\n	global $zem_contact_error, $zem_contact_submit, $zem_contact_from, $zem_contact_recipient;\n\n	extract(zem_contact_lAtts(array(\n		\'default\'	=> \'\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'email\'),\n		\'max\'		=> 100,\n		\'min\'		=> 0,\n		\'name\'		=> \'\',\n		\'required\'	=> 1,\n		\'break\'		=> br,\n		\'size\'		=> \'\',\n		\'send_article\'	=> 0\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	$email = $zem_contact_submit ? trim(ps($name)) : $default;\n\n	if ($zem_contact_submit and strlen($email))\n	{\n		if (!is_valid_email($email))\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'invalid_email\', htmlspecialchars($email));\n			$isError = \"errorElement\";\n		}\n\n		else\n		{\n			preg_match(\"/@(.+)$/\", $email, $match);\n			$domain = $match[1];\n\n			if (is_callable(\'checkdnsrr\') and checkdnsrr(\'textpattern.com.\',\'A\') and !checkdnsrr($domain.\'.\',\'MX\') and !checkdnsrr($domain.\'.\',\'A\'))\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_host\', htmlspecialchars($domain));\n				$isError = \"errorElement\";\n			}\n\n			else\n			{\n				if ($send_article) {\n					$zem_contact_recipient = $email;\n				}\n				else {\n					$zem_contact_from = $email;\n				}\n			}\n		}\n	}\n\n	return zem_contact_text(array(\n		\'default\'	=> $email,\n		\'isError\'	=> $isError,\n		\'label\'		=> $label,\n		\'max\'		=> $max,\n		\'min\'		=> $min,\n		\'name\'		=> $name,\n		\'required\'	=> $required,\n		\'break\'		=> $break,\n		\'size\'		=> $size\n	));\n}\n\nfunction zem_contact_select($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'name\'		=> \'\',\n		\'break\'		=> \' \',\n		\'delimiter\'	=> \',\',\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'option\'),\n		\'list\'		=> zem_contact_gTxt(\'general_inquiry\'),\n		\'required\'	=> 1,\n		\'selected\'	=> \'\'\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	$list = array_map(\'trim\', split($delimiter, preg_replace(\'/[\\r\\n\\t\\s]+/\', \' \',$list)));\n\n	if ($zem_contact_submit)\n	{\n		$value = trim(ps($name));\n\n		if (strlen($value))\n		{\n			if (in_array($value, $list))\n			{\n				zem_contact_store($name, $label, $value);\n			}\n\n			else\n			{\n				$zem_contact_error[] = zem_contact_gTxt(\'invalid_value\', htmlspecialchars($label), htmlspecialchars($value));\n				$isError = \"errorElement\";\n			}\n		}\n\n		elseif ($required)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', htmlspecialchars($label));\n			$isError = \"errorElement\";\n		}\n	}\n	else\n	{\n		$value = $selected;\n	}\n\n	$out = \'\';\n\n	foreach ($list as $item)\n	{\n		$out .= n.t.\'<option\'.($item == $value ? \' selected=\"selected\">\' : \'>\').(strlen($item) ? htmlspecialchars($item) : \' \').\'</option>\';\n	}\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n	return \'<label for=\"\'.$name.\'\" class=\"zemSelect \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\'.$break.\n		n.\'<select id=\"\'.$name.\'\" name=\"\'.$name.\'\" class=\"zemSelect \'.$zemRequired.$isError.\'\">\'.\n			$out.\n		n.\'</select>\';\n}\n\nfunction zem_contact_checkbox($atts)\n{\n	global $zem_contact_error, $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> \' \',\n		\'checked\'	=> 0,\n		\'isError\'	=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'checkbox\'),\n		\'name\'		=> \'\',\n		\'required\'	=> 1\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if ($zem_contact_submit)\n	{\n		$value = (bool) ps($name);\n\n		if ($required and !$value)\n		{\n			$zem_contact_error[] = zem_contact_gTxt(\'field_missing\', htmlspecialchars($label));\n			$isError = \"errorElement\";\n		}\n\n		else\n		{\n			zem_contact_store($name, $label, $value ? gTxt(\'yes\') : gTxt(\'no\'));\n		}\n	}\n\n	else {\n		$value = $checked;\n	}\n\n	$zemRequired = $required ? \'zemRequired\' : \'\';\n\n	return \'<input type=\"checkbox\" id=\"\'.$name.\'\" class=\"zemCheckbox \'.$zemRequired.$isError.\'\" name=\"\'.$name.\'\"\'.\n		($value ? \' checked=\"checked\"\' : \'\').\' />\'.$break.\n		\'<label for=\"\'.$name.\'\" class=\"zemCheckbox \'.$zemRequired.$isError.\' \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\';\n}\n\nfunction zem_contact_serverinfo($atts)\n{\n	global $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'label\'		=> \'\',\n		\'name\'		=> \'\'\n	), $atts));\n\n	if (empty($name)) $name = zem_contact_label2name($label);\n\n	if (strlen($name) and $zem_contact_submit)\n	{\n		if (!$label) $label = $name;\n		zem_contact_store($name, $label, serverSet($name));\n	}\n}\n\nfunction zem_contact_secret($atts, $thing = \'\')\n{\n	global $zem_contact_submit;\n\n	extract(zem_contact_lAtts(array(\n		\'name\'	=> \'\',\n		\'label\'	=> zem_contact_gTxt(\'secret\'),\n		\'value\'	=> \'\'\n	), $atts));\n\n	$name = zem_contact_label2name($name ? $name : $label);\n\n	if ($zem_contact_submit)\n	{\n		if ($thing) $value = trim(parse($thing));\n		zem_contact_store($name, $label, $value);\n	}\n\n	return \'\';\n}\n\nfunction zem_contact_radio($atts)\n{\n	global $zem_contact_error, $zem_contact_submit, $zem_contact_values;\n\n	extract(zem_contact_lAtts(array(\n		\'break\'		=> \' \',\n		\'checked\'	=> 0,\n		\'group\'		=> \'\',\n		\'label\'		=> zem_contact_gTxt(\'option\'),\n		\'name\'		=> \'\'\n	), $atts));\n\n	static $cur_name = \'\';\n	static $cur_group = \'\';\n\n	if (!$name and !$group and !$cur_name and !$cur_group) {\n		$cur_group = zem_contact_gTxt(\'radio\');\n		$cur_name = $cur_group;\n	}\n	if ($group and !$name and $group != $cur_group) $name = $group;\n\n	if ($name) $cur_name = $name;\n	else $name = $cur_name;\n\n	if ($group) $cur_group = $group;\n	else $group = $cur_group;\n\n	$id   = \'q\'.md5($name.\'=>\'.$label);\n	$name = zem_contact_label2name($name);\n\n	if ($zem_contact_submit)\n	{\n		$is_checked = (ps($name) == $id);\n\n		if ($is_checked or $checked and !isset($zem_contact_values[$name]))\n		{\n			zem_contact_store($name, $group, $label);\n		}\n	}\n\n	else\n	{\n		$is_checked = $checked;\n	}\n\n	return \'<input value=\"\'.$id.\'\" type=\"radio\" id=\"\'.$id.\'\" class=\"zemRadio \'.$name.\'\" name=\"\'.$name.\'\"\'.\n		( $is_checked ? \' checked=\"checked\" />\' : \' />\').$break.\n		\'<label for=\"\'.$id.\'\" class=\"zemRadio \'.$name.\'\">\'.htmlspecialchars($label).\'</label>\';\n}\n\nfunction zem_contact_send_article($atts)\n{\n	if (!isset($_REQUEST[\'zem_contact_send_article\'])) {\n		$linktext = (empty($atts[\'linktext\'])) ? zem_contact_gTxt(\'send_article\') : $atts[\'linktext\'];\n		$join = (empty($_SERVER[\'QUERY_STRING\'])) ? \'?\' : \'&\';\n		$href = $_SERVER[\'REQUEST_URI\'].$join.\'zem_contact_send_article=yes\';\n		return \'<a href=\"\'.htmlspecialchars($href).\'\">\'.htmlspecialchars($linktext).\'</a>\';\n	}\n	return;\n}\n\nfunction zem_contact_submit($atts, $thing)\n{\n	extract(zem_contact_lAtts(array(\n		\'button\'	=> 0,\n		\'label\'		=> zem_contact_gTxt(\'send\')\n	), $atts));\n\n	$label = htmlspecialchars($label);\n\n	if ($button or strlen($thing))\n	{\n		return \'<button type=\"submit\" class=\"zemSubmit\" name=\"zem_contact_submit\" value=\"\'.$label.\'\">\'.($thing ? trim(parse($thing)) : $label).\'</button>\';\n	}\n	else\n	{\n		return \'<input type=\"submit\" class=\"zemSubmit\" name=\"zem_contact_submit\" value=\"\'.$label.\'\" />\';\n	}\n}\n\nfunction zem_contact_lAtts($arr, $atts)\n{\n	foreach(array(\'button\', \'copysender\', \'checked\', \'required\', \'send_article\', \'show_input\', \'show_error\') as $key)\n	{\n		if (isset($atts[$key]))\n		{\n			$atts[$key] = ($atts[$key] === \'yes\' or intval($atts[$key])) ? 1 : 0;\n		}\n	}\n	if (isset($atts[\'break\']) and $atts[\'break\'] == \'br\') $atts[\'break\'] = \'<br />\';\n	return lAtts($arr, $atts);\n}\n\nclass zemcontact_evaluation\n{\n	var $status;\n\n	function zemcontact_evaluation() {\n		$this->status = 0;\n	}\n\n	function add_zemcontact_status($check) {\n		$this->status += $check;\n	}\n\n	function get_zemcontact_status() {\n		return $this->status;\n	}\n}\n\nfunction &get_zemcontact_evaluator()\n{\n	static $instance;\n\n	if(!isset($instance)) {\n		$instance = new zemcontact_evaluation();\n	}\n	return $instance;\n}\n\nfunction zem_contact_label2name($label)\n{\n	$label = trim($label);\n	if (strlen($label) == 0) return \'invalid\';\n	if (strlen($label) <= 32 and preg_match(\'/^[a-zA-Z][A-Za-z0-9:_-]*$/\', $label)) return $label;\n	else return \'q\'.md5($label);\n}\n\nfunction zem_contact_store($name, $label, $value)\n{\n	global $zem_contact_form, $zem_contact_labels, $zem_contact_values;\n	$zem_contact_form[$label] = $value;\n	$zem_contact_labels[$name] = $label;\n	$zem_contact_values[$name] = $value;\n}\n\nfunction zem_contact_mailheader($string, $type)\n{\n	global $prefs;\n	if (!strstr($string,\'=?\') and !preg_match(\'/[\\x00-\\x1F\\x7F-\\xFF]/\', $string)) {\n		if (\"phrase\" == $type) {\n			if (preg_match(\'/[][()<>@,;:\".\\x5C]/\', $string)) {\n				$string = \'\"\'. strtr($string, array(\"\\\\\" => \"\\\\\\\\\", \'\"\' => \'\\\"\')) . \'\"\';\n			}\n		}\n		elseif (\"text\" != $type) {\n			trigger_error(\'Unknown encode_mailheader type\', E_USER_WARNING);\n		}\n		return $string;\n	}\n	if ($prefs[\'override_emailcharset\']) {\n		$start = \'=?ISO-8859-1?B?\';\n		$pcre  = \'/.{1,42}/s\';\n	}\n	else {\n		$start = \'=?UTF-8?B?\';\n		$pcre  = \'/.{1,45}(?=[\\x00-\\x7F\\xC0-\\xFF]|$)/s\';\n	}\n	$end = \'?=\';\n	$sep = is_windows() ? \"\\r\\n\" : \"\\n\";\n	preg_match_all($pcre, $string, $matches);\n	return $start . join($end.$sep.\' \'.$start, array_map(\'base64_encode\',$matches[0])) . $end;\n}\n','cb772f305727a9e9e5fd7d1616f56996',0,5,0),('zem_contact_lang',1,'TXP Community','http://forum.textpattern.com/viewtopic.php?id=21144','4.0.3.6','Language plug-in for Zem Contact Reborn','<div style=\"text-align:center;font-weight:bold;font-size:24px;text-decoration:underline;\">Zem Contact Lang</div>\n\n	<p>This is a separate language plug-in for use with Zem Contact Reborn. Both plug-ins need to be installed and activated in order to work properly.</p>\n\n	<p>Separating the language in this way will enable non-english users to update the main plug-in without affecting their &#8220;localisation&#8221;.</p>\n\n<div id=\"local\" style=\"text-align:center;font-weight:bold;font-size:24px;text-decoration:underline;\">Localisation</div>\n\n	<p>Throughout the <code>zem_contact_reborn</code> plug-in, use has been made of a separate <code>gTxt</code> function which you can see in this plug-in&#8217;s code by clicking on the &#8220;Edit&#8221; button.</p>\n\n	<p>If you are using the plug-in for a non-english site you can make use of this to localise text outputs for your preferred language.</p>\n\n	<p>You should only edit text that appears after the <code>=&gt;</code> sign.</p>\n\n	<p>If you have a dual-language site and the languages use separate &#8220;sections&#8221;, you can use the <txp:if_section> tag to enable different translations. An example of this usage is shown in the <strong>&#8220;forum thread&#8221;:http://forum.textpattern.com/viewtopic.php?id=13416</strong>. Our thanks to Els (doggiez) for this example.</p>\n\n <br />\n','\nfunction zem_contact_gTxt($what, $var1 = \'\', $var2 = \'\')\n{\n	$lang = array(\n		\'checkbox\'		=> \'Checkbox\',\n		\'contact\'		=> \'Contact\',\n		\'email\'			=> \'Email\',\n		\'email_subject\'		=> \"$var1 > Inquiry\",\n		\'email_thanks\'		=> \'Thank you, your message has been sent.\',\n		\'field_missing\'		=> \"Required field, &#8220;<strong>$var1</strong>&#8221;, is missing.\",\n		\'form_expired\'		=> \'The form has expired, please try again.\',\n		\'form_used\'		=> \'The form was already submitted, please fill out a new form.\',\n		\'general_inquiry\'	=> \'General inquiry\',\n		\'invalid_email\'		=> \"&#8220;<strong>$var1</strong>&#8221; is not a valid email address.\",\n		\'invalid_host\'		=> \"&#8220;<strong>$var1</strong>&#8221; is not a valid email host.\",\n		\'invalid_utf8\'		=> \"&#8220;<strong>$var1</strong>&#8221; contains invalid UTF-8 characters.\",\n		\'invalid_value\'		=> \"Invalid value for &#8220;<strong>$var1</strong>&#8221;, &#8220;<strong>$var2</strong>&#8221; is not one of the available options.\",\n		\'mail_sorry\'		=> \'Sorry, unable to send email.\',\n		\'message\'		=> \'Message\',\n		\'min_warning\'		=> \"&#8220;<strong>$var1</strong>&#8221; must contain at least $var2 characters.\",\n		\'max_warning\'		=> \"&#8220;<strong>$var1</strong>&#8221; must not contain more than $var2 characters.\",\n		\'name\'			=> \'Name\',\n		\'option\'		=> \'Option\',\n		\'radio\'			=> \'Radio\',\n		\'recipient\'		=> \'Recipient\',\n		\'refresh\'		=> \'Follow this link if the page does not refresh automatically.\',\n		\'secret\'		=> \'Secret\',\n		\'send\'			=> \'Send\',\n		\'send_article\'		=> \'Send article\',\n		\'spam\'			=> \'We do not accept spam, thank you!\',\n		\'text\'			=> \'Text\',\n		\'to_missing\'		=> \'&#8220;<strong>To</strong>&#8221; email address is missing.\',\n		\'version\'		=> \'4.0.3.6\'\n	);\n\n	return $lang[$what];\n}\n','\nfunction zem_contact_gTxt($what, $var1 = \'\', $var2 = \'\')\n{\n	$lang = array(\n		\'checkbox\'		=> \'Checkbox\',\n		\'contact\'		=> \'Contact\',\n		\'email\'			=> \'Email\',\n		\'email_subject\'		=> \"$var1 > Inquiry\",\n		\'email_thanks\'		=> \'Thank you, your message has been sent.\',\n		\'field_missing\'		=> \"Required field, &#8220;<strong>$var1</strong>&#8221;, is missing.\",\n		\'form_expired\'		=> \'The form has expired, please try again.\',\n		\'form_used\'		=> \'The form was already submitted, please fill out a new form.\',\n		\'general_inquiry\'	=> \'General inquiry\',\n		\'invalid_email\'		=> \"&#8220;<strong>$var1</strong>&#8221; is not a valid email address.\",\n		\'invalid_host\'		=> \"&#8220;<strong>$var1</strong>&#8221; is not a valid email host.\",\n		\'invalid_utf8\'		=> \"&#8220;<strong>$var1</strong>&#8221; contains invalid UTF-8 characters.\",\n		\'invalid_value\'		=> \"Invalid value for &#8220;<strong>$var1</strong>&#8221;, &#8220;<strong>$var2</strong>&#8221; is not one of the available options.\",\n		\'mail_sorry\'		=> \'Sorry, unable to send email.\',\n		\'message\'		=> \'Message\',\n		\'min_warning\'		=> \"&#8220;<strong>$var1</strong>&#8221; must contain at least $var2 characters.\",\n		\'max_warning\'		=> \"&#8220;<strong>$var1</strong>&#8221; must not contain more than $var2 characters.\",\n		\'name\'			=> \'Name\',\n		\'option\'		=> \'Option\',\n		\'radio\'			=> \'Radio\',\n		\'recipient\'		=> \'Recipient\',\n		\'refresh\'		=> \'Follow this link if the page does not refresh automatically.\',\n		\'secret\'		=> \'Secret\',\n		\'send\'			=> \'Send\',\n		\'send_article\'		=> \'Send article\',\n		\'spam\'			=> \'We do not accept spam, thank you!\',\n		\'text\'			=> \'Text\',\n		\'to_missing\'		=> \'&#8220;<strong>To</strong>&#8221; email address is missing.\',\n		\'version\'		=> \'4.0.3.6\'\n	);\n\n	return $lang[$what];\n}\n','552fe2e408499f9fd92ab620fa0e15f6',0,5,0),('rss_thumbpop',0,'Rob Sable','http://www.wilshireone.com/','0.7','Flexible thumbnail image gallery in table or float format.','\n<hr/>\n<p align=\"center\"><a href=\"http://www.wilshireone.com/textpattern-plugins/rss-thumbpop\">Latest Documentation</a></p>\n<hr/>\n\n	<p>Here are the major functions of the plugin:\n	<ul>\n		<li>Generates a thumbnail gallery using a table or floated divs</li>\n		<li>Allows all categories, multiple categories or use of the global category\n		<li>Thumbnails are hyperlinked\n	<ul>\n		<li>and shown in a popup of the full size image only</li>\n		<li>and shown in a popup page with the full size image and caption</li>\n		<li>and the full size image is shown on the same page after a reload</li>\n	</ul></li>\n	<ul>\n		<li>and the full size image is shown on the same page using javascript with no reload</li>\n	</ul></li>\n		<li>Can be used to automatically show a gallery based on the current article ID</li>\n		<li>Supports paging</li>\n		<li>Images can be ordered by name, caption, date asc, date desc or random</li>\n		<li>Define the padding around the image in the popup window</li>\n		<li>Define the number of images per row</li>\n		<li>Optionally show image captions in thumbnail view</li>\n		<li>Optionally show image alt text in thumbnail view</li>\n		<li>Optionally include a header label in thumbnail view</li>\n		<li>Optionally turn popups off</li>\n	</ul>\n	<ul>\n		<li>Built in classes rssThumbs, rssThumbLabel, rssThumb, rssImg, rssThumbFloat for easy <span class=\"caps\">CSS</span> styling</li>\n	</ul></p>\n\n<hr/>\n\n	<p><strong>IMPORTANT:</strong> If you are using &#8220;float&#8221; mode you must add styling for the rssThumbFloat class. See the example at the bottom or check the <a href=\"http://css.maxdesign.com.au/floatutorial/tutorial0407.htm\">Floatutorial</a>.</p>\n\n	<p><strong>IMPORTANT:</strong> If you are using the showpagelinks default setting with paging you must add styling for the rssThumbNav id. See the example at the bottom or check the <a href=\"http://css.maxdesign.com.au/floatutorial/tutorial0513.htm\">Floatutorial</a>.</p>\n\n	<p><strong>TIP:</strong> Use the <a href=\"http://johan.galaxen.net/logg/111/textpattern-plugin-glx-admin-image\">glx_admin_image</a> plugin to make your life a lot easier.</p>\n\n<hr/>\n\n	<p>Full documentation for the tags parameters is as follows:</p>\n\n	<p><strong>category</strong><br />\nAccepts a comma separate list of categories.  NO spaces.  If currently browsing by category, the global category will be used as the default.<br />\nDefault:  ','\n// rss_thumbpop thumbnail image gallery plugin\n// by Rob Sable\n// http://www.wilshireone.com\n// Version 0.1 - 12/07/2004 - Initial Release\n// Version 0.2 - 12/08/2004 - Added paging support with use of limit, showpagelinks, backlabel and nextlabel properties.\n// Version 0.3 - 1/10/2005 - Added articlethumbs property to automatically show a gallery named \"article-\" + the current article ID.\n// Version 0.4 - 1/10/2005 - Added orderby, pagepop using thumbpop.php, padheight, padwidth.\n// Version 0.5 - 5/1/2005 - Added divpop, jpop, showblank, blankimg, clickonly, usearticle, catfield, addpermlink, fullontop, allcats, showalt, orderby alt + random, thumbpop.php is no longer needed.\n// Version 0.6 - 1/4/2006 - Added orderby namedesc, fixed validation errors, fixed paging links\n// Version 0.6.1 - 1/10/2006 - Fixed paging again.  Added showfullcaption for jpop.\n// Version 0.7 - 8/2/2006 - Added showfullalt for jpop.  (Sponsored by mrdale)\n\nfunction rss_thumbpop($atts) {\nglobal $img_dir,$txpcfg,$pretext,$thisarticle;\nextract($atts);\nextract($pretext);\n\n$mode = isset($mode) ? $mode: \"table\";\n$cols = isset($cols) ? $cols: \"3\";\n$label = isset($label) ? $label: \"\";\n$showcaption = isset($showcaption) ? $showcaption: \"1\";\n$showalt = isset($showalt) ? $showalt: \"0\";\n$nopop = isset($nopop) ? $nopop: \"0\";\n$category = isset($category) ? doSlash($category) : $c ;\n$limit= isset($limit) ? $limit: \"99999\";\n$offset= isset($offset) ? $offset: \"0\";\n$showpagelinks= isset($showpagelinks) ? $showpagelinks: \"1\";\n$backlabel= isset($backlabel) ? $backlabel: \"Back\";\n$nextlabel= isset($nextlabel) ? $nextlabel: \"Next\";\n$articlethumbs= isset($articlethumbs) ? $articlethumbs: \"0\";\n$orderby = isset($orderby) ? $orderby: \"\";\n$pagepop = isset($pagepop) ? $pagepop: \"0\";\n$padheight = isset($padheight) ? $padheight: \"20\";\n$padwidth = isset($padwidth) ? $padwidth: \"20\";\n$divpop = isset($divpop) ? $divpop: \"0\";\n$fullontop = isset($fullontop) ? $fullontop: \"1\";\n$showfullcaption = isset($showfullcaption) ? $showfullcaption: \"0\";\n$showfullalt = isset($showfullalt) ? $showfullalt: \"0\";\n$allcats = isset($allcats) ? $allcats: \"0\";\n$jpop = isset($jpop) ? $jpop: \"0\";\n$showblank = isset($showblank) ? $showblank: \"0\";\n$blankimg = isset($blankimg) ? $blankimg: \"/img/blankphoto.jpg\";\n$clickonly = isset($clickonly) ? $clickonly: \"0\";\n$usearticle = isset($usearticle) ? $usearticle: \"0\";\n$catfield = isset($catfield) ? $catfield: \"custom_1\";\n$addpermlink = isset($addpermlink) ? $addpermlink: \"1\";\n$artcat = \"\";\n$divimg = \"\";\n$i=0;\n\nif ($usearticle) {\n	$id = $thisarticle[\"thisid\"];\n	$res = safe_rows(\"*, unix_timestamp(Posted) as uPosted\", \"textpattern\", \"id = \".$id);\n\n	if ($res) {\n		foreach($res as $a) {\n			extract($a);\n			populateArticleData($a);\n			$artcat = \" AND (category = \'\" . doSlash($a[$catfield]) . \"\') \";\n			$artlink = permlinkurl($a);\n		}\n	}\n}\n\nforeach (explode(\',\', $category) as $category) {\n	$catsql[] = ($category) ? \" (category = \'\" . doSlash($category) . \"\') \" : \"\";\n}\n$categories = (!$allcats && $category) ? \'(\' . join(\' OR \', $catsql) . \')\' : \'1=1 \';\n\n\nif  ($articlethumbs) {\n	$categories = \" (category = \'\" . doSlash(\'article-\' . $thisarticle[\'thisid\']) . \"\') \";\n}\n\nswitch ($orderby) {\ncase \"name\":\n   $obfield=\" ORDER BY name\";\n   break;\ncase \"namedesc\":\n   $obfield=\" ORDER BY name desc\";\n   break;\ncase \"caption\":\n   $obfield=\" ORDER BY caption\";\n   break;\ncase \"alt\":\n   $obfield=\" ORDER BY alt\";\n   break;\ncase \"dateasc\":\n   $obfield=\" ORDER BY date asc\";\n   break;\ncase \"datedesc\":\n   $obfield=\" ORDER BY date desc\";\n   break;\ncase \"random\":\n   $obfield=\" ORDER BY rand()\";\n   break;\ndefault:\n	$obfield=\"\";\n}\n\nif ($limit && $showpagelinks) {\n\n\n	// DO PAGING\n	$where = $categories.$artcat.$obfield.\' LIMIT \'.$offset.\',99999\';\n	$results = safe_rows(\'*\', \'txp_image\', $where);\n	$numthum = count($results);\n\n	$numPages = ($numthum > 0 && $limit) ? ceil($numthum/$limit) : 1;\n	$thumbpage = (!gps(\'tpg\')) ? 1 : gps(\'tpg\');\n	$offset = ($thumbpage - 1) * $limit;\n	$results = safe_rows(\'*\', \'txp_image\', $categories.$obfield.\' LIMIT \'.$offset.\',\'.$limit);\n\n} else {\n\n	//NO PAGING\n	$numPages = 0;\n	$where = $categories.$artcat.$obfield.\' LIMIT \'.$offset.\',\'.$limit;\n	$results = safe_rows(\'*\', \'txp_image\', $where);\n	$numthum = count($results);\n\n	if ($numthum == 0 && $articlethumbs) {\n		return;\n	}\n\n}\n\nif ($mode==\"table\") {\n	$head = \'<table class=\"rssThumbs\">\'.n;\n	$head.= ($label) ? \'<tr><th class=\"rssThumbLabel\" colspan=\"\' . $cols . \'\">\'. $label .\'</th></tr>\'.n : \'\';\n	$head.= \'<tr>\'.n;\n} else 	if ($mode == \"float\") {\n	$head = \'<div class=\"rssThumbs\">\';\n	$head.= ($label) ? \'<div class=\"rssThumbLabel\">\'. $label .\'</div>\'.n : \'\';\n}\n\nif($results){\n	foreach($results as $image){\n		extract($image);\n		$thumb =  hu.$img_dir.\'/\' . $id . \'t\' . $ext;\n		$full = hu.$img_dir.\'/\' . $id . $ext;\n\n		$divimg = (gps(\"img\") && ($id == gps(\"img\")) && $divpop) ? \'<div class=\"rssFull\"><img src=\"\'  . $full . \'\" alt=\"\'.$alt.\'\" /></div>\'.n : $divimg;\n\n		$img = (isset($artlink) && $addpermlink) ? href(\'<img class=\"rssThumb\" src=\"\'  . $thumb . \'\" alt=\"\'.$alt.\'\" title=\"\'.$caption.\'\" />\',$artlink) : \'<img class=\"rssThumb\" src=\"\'  . $thumb . \'\" alt=\"\'.$alt.\'\" title=\"\'.$caption.\'\" />\';\n\n		if (!$nopop ) {\n			if ($pagepop) {\n				$page = hu . \"index.php?file=thumbpop&amp;pic=\" . $id;\n				$imgtag = join(\"\",array(\n					\" <a target=\\\"_blank\\\" href=\\\"\".$page.\"\\\"\",\n					\" onclick=\\\"\",\"window.open(this.href, \'popupwindow\', \'width=\",$w+$padwidth,\",height=\",$h+$padheight,\n					\",resizable\'); return false;\\\">\",\n					$img,\"</a>\"));\n			} else if ($divpop) {\n				$imgtag = \'<a href=\"?img=\'.$id.\'\">\'.$img.\'</a>\';\n			} else if ($jpop) {\n				$events = ($clickonly) ? \'onclick=\"return showPic(this)\"\' : \'onmouseover=\"return showPic(this)\" onclick=\"return showPic(this)\"\';\n				$imgtit = ($showfullalt) ? $alt.\"|\".$caption : $caption;\n				$imgtag = \'<a \'.$events.\' href=\"\'.$full.\'\" title=\"\'.$imgtit.\'\">\'.$img.\'</a>\';\n				$blankimg = ($showblank) ? $blankimg : $full;\n				$divimg = \'<div id=\"fullsize\"><div id=\"desc\">Mouse over a thumbnail to view</div>\';\n				$divimg .= ($showfullalt) ? \'<div id=\"jpopalt\">\'.$alt.\'</div>\' : \'\';\n				$divimg .= \'<img id=\"placeholder\" src=\"\'.$blankimg.\'\" alt=\"\" />\';\n				$divimg .= ($showfullcaption) ? \'<div id=\"jpopcap\">\'.$caption.\'</div>\' : \'\';\n				$divimg .= \'</div>\';\n			} else {\n				$imgtag = join(\"\",array(\n					\" <a target=\\\"_blank\\\" href=\\\"\".$full.\"\\\"\",\n					\" onclick=\\\"\",\"window.open(this.href, \'popupwindow\', \'width=\",$w+$padwidth,\",height=\",$h+$padheight,\n					\",resizable\'); return false;\\\">\",\n					$img,\"</a>\"));\n			}\n		} else {\n			$imgtag = $img;\n		}\n\n		$numthum--;\n\n		if ($mode == \"table\") {\n			$output[] =  \'<td valign=\"top\"><div class=\"rssImg\">\';\n			$output[] = $imgtag.\'</div>\';\n			$output[] = ($showalt && $alt) ? n.\'<span class=\"cap\">\'.$alt.\'</span>\'.n : \'\';\n			$output[] = ($showcaption && $caption) ? \'<span class=\"cap\">\'.$caption.\'</span>\'.n : \'\';\n			$output[] = \'</td>\'.n;\n			if($i++ % $cols == ($cols - 1) && $numthum > 0) $output[]= \'</tr>\' .n . \'<tr>\'.n;\n		} else	if ($mode == \"float\") {\n			$output [] =  \'<div class=\"rssThumbFloat\">\'.n;\n			$output[] = $imgtag;\n			$output[] = ($showalt && $alt) ? n.\'<span class=\"cap\">\'.$alt.\'</span>\'.n : \'\';\n			$output[] = ($showcaption && $caption) ? \'<span class=\"cap\">\'.$caption.\'</span>\'.n : \'\';\n			$output[] = \'</div>\'.n;\n			if($i++ % $cols == ($cols - 1) && $numthum > 0) $output[]= \'<br style=\"clear: both;\" />\'.n;\n		}\n	}\n} else {\n$output[]= ($mode == \"table\") ? \'<td class=\"rssImg\"  colspan=\"\' . $cols . \'\">No Images Found</td>\'.n : \'No Images Found\';\n}\n$output[] = ($mode == \"table\") ? n.\'</tr>\'.n.\'</table>\'.n : \'<br style=\"clear: both;\" /></div>\'.n;\n\nif ($numPages > 1 && $showpagelinks) {\n	$next = ($numPages > 1 && $thumbpage != $numPages);\n	$back = ($numPages > 1 && $thumbpage > 1);\n	$output[] = \'<ul id=\"rssThumbNav\">\'.n;\n	$output[] = ($back) ? \'<li class=\"left\"><a href=\"?tpg=\'.($thumbpage-1).\'\">\'.$backlabel.\'</a></li>\'.n : \'\';\n	$output[] = ($next) ? \'<li class=\"right\"><a href=\"?tpg=\'.($thumbpage+1).\'\">\'.$nextlabel.\'</a></li>\'.n : \'\';\n	$output[] = \'</ul>\'.n;\n}\n\n$jpop = ($jpop) ? jsPop() : \'\';\n\nreturn ($fullontop) ? $divimg.$head.implode(\'\', $output).$jpop : $head.implode(\'\', $output).$divimg.$jpop;\n}\n\nfunction jsPop() {\nreturn <<<EOF\n<script language=\"JavaScript\" type=\"text/javascript\">\n<!--\n	// Javascript Image Gallery by Jeremy Keith\n	// http://adactio.com/articles/display.php/javascript_image_gallery\n	function showPic (whichpic) {\n		if (document.getElementById) {\n			document.getElementById(\'placeholder\').src = whichpic.href;\n			if (whichpic.title) {\n				 var rssText = whichpic.title;\n				 txtt = rssText.substring(rssText.indexOf(\'|\') + 1, rssText.length);\n				 altt = rssText.substring(0,rssText.indexOf(\'|\'));\n				 if (document.getElementById(\'jpopcap\')) document.getElementById(\'jpopcap\').childNodes[0].nodeValue = txtt;\n				 if (document.getElementById(\'jpopalt\')) document.getElementById(\'jpopalt\').childNodes[0].nodeValue = altt;\n			} else {\n				 if (document.getElementById(\'jpopcap\')) document.getElementById(\'jpopcap\').childNodes[0].nodeValue = whichpic.childNodes[0].nodeValue;\n				 if (document.getElementById(\'jpopalt\')) document.getElementById(\'jpopalt\').childNodes[0].nodeValue = whichpic.childNodes[0].nodeValue;\n			}\n			return false;\n		} else {\n			return true;\n		}\n	}\n	-->\n	</script>\nEOF;\n}\n\nif (gps(\'file\') == \'thumbpop\') {\n$id = $_GET[\"pic\"];\nif (!$id) { return; }\nglobal $pfr,$img_dir;\n$get = safe_row(\"*\",\"txp_image\",\"id=\'$id\'\");\nextract($get);\n\necho <<<EOF\n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n  <head>\n    <title>\nEOF;\n			echo $alt;\necho <<<EOF\n		</title>\n		<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n		<style type=\"text/css\" media=\"screen\">\n			<!--\n			p { font: .8em Verdana, sans-serif; text-align: center; }\n			img { padding: 2px; border: 1px solid #555; }\n			-->\n		</style>\n  </head>\n  <body>\nEOF;\n		echo \'<img src=\"\'  . $pfr.$img_dir.\'/\' . $id . $ext . \'\" alt=\"\'.$alt.\'\" /><p>\' . $caption .\'</p>\';\necho <<<EOF\n  </body>\n</html>\n\nEOF;\nexit;\n}\n','\n// rss_thumbpop thumbnail image gallery plugin\n// by Rob Sable\n// http://www.wilshireone.com\n// Version 0.1 - 12/07/2004 - Initial Release\n// Version 0.2 - 12/08/2004 - Added paging support with use of limit, showpagelinks, backlabel and nextlabel properties.\n// Version 0.3 - 1/10/2005 - Added articlethumbs property to automatically show a gallery named \"article-\" + the current article ID.\n// Version 0.4 - 1/10/2005 - Added orderby, pagepop using thumbpop.php, padheight, padwidth.\n// Version 0.5 - 5/1/2005 - Added divpop, jpop, showblank, blankimg, clickonly, usearticle, catfield, addpermlink, fullontop, allcats, showalt, orderby alt + random, thumbpop.php is no longer needed.\n// Version 0.6 - 1/4/2006 - Added orderby namedesc, fixed validation errors, fixed paging links\n// Version 0.6.1 - 1/10/2006 - Fixed paging again.  Added showfullcaption for jpop.\n// Version 0.7 - 8/2/2006 - Added showfullalt for jpop.  (Sponsored by mrdale)\n\nfunction rss_thumbpop($atts) {\nglobal $img_dir,$txpcfg,$pretext,$thisarticle;\nextract($atts);\nextract($pretext);\n\n$mode = isset($mode) ? $mode: \"table\";\n$cols = isset($cols) ? $cols: \"3\";\n$label = isset($label) ? $label: \"\";\n$showcaption = isset($showcaption) ? $showcaption: \"1\";\n$showalt = isset($showalt) ? $showalt: \"0\";\n$nopop = isset($nopop) ? $nopop: \"0\";\n$category = isset($category) ? doSlash($category) : $c ;\n$limit= isset($limit) ? $limit: \"99999\";\n$offset= isset($offset) ? $offset: \"0\";\n$showpagelinks= isset($showpagelinks) ? $showpagelinks: \"1\";\n$backlabel= isset($backlabel) ? $backlabel: \"Back\";\n$nextlabel= isset($nextlabel) ? $nextlabel: \"Next\";\n$articlethumbs= isset($articlethumbs) ? $articlethumbs: \"0\";\n$orderby = isset($orderby) ? $orderby: \"\";\n$pagepop = isset($pagepop) ? $pagepop: \"0\";\n$padheight = isset($padheight) ? $padheight: \"20\";\n$padwidth = isset($padwidth) ? $padwidth: \"20\";\n$divpop = isset($divpop) ? $divpop: \"0\";\n$fullontop = isset($fullontop) ? $fullontop: \"1\";\n$showfullcaption = isset($showfullcaption) ? $showfullcaption: \"0\";\n$showfullalt = isset($showfullalt) ? $showfullalt: \"0\";\n$allcats = isset($allcats) ? $allcats: \"0\";\n$jpop = isset($jpop) ? $jpop: \"0\";\n$showblank = isset($showblank) ? $showblank: \"0\";\n$blankimg = isset($blankimg) ? $blankimg: \"/img/blankphoto.jpg\";\n$clickonly = isset($clickonly) ? $clickonly: \"0\";\n$usearticle = isset($usearticle) ? $usearticle: \"0\";\n$catfield = isset($catfield) ? $catfield: \"custom_1\";\n$addpermlink = isset($addpermlink) ? $addpermlink: \"1\";\n$artcat = \"\";\n$divimg = \"\";\n$i=0;\n\nif ($usearticle) {\n	$id = $thisarticle[\"thisid\"];\n	$res = safe_rows(\"*, unix_timestamp(Posted) as uPosted\", \"textpattern\", \"id = \".$id);\n\n	if ($res) {\n		foreach($res as $a) {\n			extract($a);\n			populateArticleData($a);\n			$artcat = \" AND (category = \'\" . doSlash($a[$catfield]) . \"\') \";\n			$artlink = permlinkurl($a);\n		}\n	}\n}\n\nforeach (explode(\',\', $category) as $category) {\n	$catsql[] = ($category) ? \" (category = \'\" . doSlash($category) . \"\') \" : \"\";\n}\n$categories = (!$allcats && $category) ? \'(\' . join(\' OR \', $catsql) . \')\' : \'1=1 \';\n\n\nif  ($articlethumbs) {\n	$categories = \" (category = \'\" . doSlash(\'article-\' . $thisarticle[\'thisid\']) . \"\') \";\n}\n\nswitch ($orderby) {\ncase \"name\":\n   $obfield=\" ORDER BY name\";\n   break;\ncase \"namedesc\":\n   $obfield=\" ORDER BY name desc\";\n   break;\ncase \"caption\":\n   $obfield=\" ORDER BY caption\";\n   break;\ncase \"alt\":\n   $obfield=\" ORDER BY alt\";\n   break;\ncase \"dateasc\":\n   $obfield=\" ORDER BY date asc\";\n   break;\ncase \"datedesc\":\n   $obfield=\" ORDER BY date desc\";\n   break;\ncase \"random\":\n   $obfield=\" ORDER BY rand()\";\n   break;\ndefault:\n	$obfield=\"\";\n}\n\nif ($limit && $showpagelinks) {\n\n\n	// DO PAGING\n	$where = $categories.$artcat.$obfield.\' LIMIT \'.$offset.\',99999\';\n	$results = safe_rows(\'*\', \'txp_image\', $where);\n	$numthum = count($results);\n\n	$numPages = ($numthum > 0 && $limit) ? ceil($numthum/$limit) : 1;\n	$thumbpage = (!gps(\'tpg\')) ? 1 : gps(\'tpg\');\n	$offset = ($thumbpage - 1) * $limit;\n	$results = safe_rows(\'*\', \'txp_image\', $categories.$obfield.\' LIMIT \'.$offset.\',\'.$limit);\n\n} else {\n\n	//NO PAGING\n	$numPages = 0;\n	$where = $categories.$artcat.$obfield.\' LIMIT \'.$offset.\',\'.$limit;\n	$results = safe_rows(\'*\', \'txp_image\', $where);\n	$numthum = count($results);\n\n	if ($numthum == 0 && $articlethumbs) {\n		return;\n	}\n\n}\n\nif ($mode==\"table\") {\n	$head = \'<table class=\"rssThumbs\">\'.n;\n	$head.= ($label) ? \'<tr><th class=\"rssThumbLabel\" colspan=\"\' . $cols . \'\">\'. $label .\'</th></tr>\'.n : \'\';\n	$head.= \'<tr>\'.n;\n} else 	if ($mode == \"float\") {\n	$head = \'<div class=\"rssThumbs\">\';\n	$head.= ($label) ? \'<div class=\"rssThumbLabel\">\'. $label .\'</div>\'.n : \'\';\n}\n\nif($results){\n	foreach($results as $image){\n		extract($image);\n		$thumb =  hu.$img_dir.\'/\' . $id . \'t\' . $ext;\n		$full = hu.$img_dir.\'/\' . $id . $ext;\n\n		$divimg = (gps(\"img\") && ($id == gps(\"img\")) && $divpop) ? \'<div class=\"rssFull\"><img src=\"\'  . $full . \'\" alt=\"\'.$alt.\'\" /></div>\'.n : $divimg;\n\n		$img = (isset($artlink) && $addpermlink) ? href(\'<img class=\"rssThumb\" src=\"\'  . $thumb . \'\" alt=\"\'.$alt.\'\" title=\"\'.$caption.\'\" />\',$artlink) : \'<img class=\"rssThumb\" src=\"\'  . $thumb . \'\" alt=\"\'.$alt.\'\" title=\"\'.$caption.\'\" />\';\n\n		if (!$nopop ) {\n			if ($pagepop) {\n				$page = hu . \"index.php?file=thumbpop&amp;pic=\" . $id;\n				$imgtag = join(\"\",array(\n					\" <a target=\\\"_blank\\\" href=\\\"\".$page.\"\\\"\",\n					\" onclick=\\\"\",\"window.open(this.href, \'popupwindow\', \'width=\",$w+$padwidth,\",height=\",$h+$padheight,\n					\",resizable\'); return false;\\\">\",\n					$img,\"</a>\"));\n			} else if ($divpop) {\n				$imgtag = \'<a href=\"?img=\'.$id.\'\">\'.$img.\'</a>\';\n			} else if ($jpop) {\n				$events = ($clickonly) ? \'onclick=\"return showPic(this)\"\' : \'onmouseover=\"return showPic(this)\" onclick=\"return showPic(this)\"\';\n				$imgtit = ($showfullalt) ? $alt.\"|\".$caption : $caption;\n				$imgtag = \'<a \'.$events.\' href=\"\'.$full.\'\" title=\"\'.$imgtit.\'\">\'.$img.\'</a>\';\n				$blankimg = ($showblank) ? $blankimg : $full;\n				$divimg = \'<div id=\"fullsize\"><div id=\"desc\">Mouse over a thumbnail to view</div>\';\n				$divimg .= ($showfullalt) ? \'<div id=\"jpopalt\">\'.$alt.\'</div>\' : \'\';\n				$divimg .= \'<img id=\"placeholder\" src=\"\'.$blankimg.\'\" alt=\"\" />\';\n				$divimg .= ($showfullcaption) ? \'<div id=\"jpopcap\">\'.$caption.\'</div>\' : \'\';\n				$divimg .= \'</div>\';\n			} else {\n				$imgtag = join(\"\",array(\n					\" <a target=\\\"_blank\\\" href=\\\"\".$full.\"\\\"\",\n					\" onclick=\\\"\",\"window.open(this.href, \'popupwindow\', \'width=\",$w+$padwidth,\",height=\",$h+$padheight,\n					\",resizable\'); return false;\\\">\",\n					$img,\"</a>\"));\n			}\n		} else {\n			$imgtag = $img;\n		}\n\n		$numthum--;\n\n		if ($mode == \"table\") {\n			$output[] =  \'<td valign=\"top\"><div class=\"rssImg\">\';\n			$output[] = $imgtag.\'</div>\';\n			$output[] = ($showalt && $alt) ? n.\'<span class=\"cap\">\'.$alt.\'</span>\'.n : \'\';\n			$output[] = ($showcaption && $caption) ? \'<span class=\"cap\">\'.$caption.\'</span>\'.n : \'\';\n			$output[] = \'</td>\'.n;\n			if($i++ % $cols == ($cols - 1) && $numthum > 0) $output[]= \'</tr>\' .n . \'<tr>\'.n;\n		} else	if ($mode == \"float\") {\n			$output [] =  \'<div class=\"rssThumbFloat\">\'.n;\n			$output[] = $imgtag;\n			$output[] = ($showalt && $alt) ? n.\'<span class=\"cap\">\'.$alt.\'</span>\'.n : \'\';\n			$output[] = ($showcaption && $caption) ? \'<span class=\"cap\">\'.$caption.\'</span>\'.n : \'\';\n			$output[] = \'</div>\'.n;\n			if($i++ % $cols == ($cols - 1) && $numthum > 0) $output[]= \'<br style=\"clear: both;\" />\'.n;\n		}\n	}\n} else {\n$output[]= ($mode == \"table\") ? \'<td class=\"rssImg\"  colspan=\"\' . $cols . \'\">No Images Found</td>\'.n : \'No Images Found\';\n}\n$output[] = ($mode == \"table\") ? n.\'</tr>\'.n.\'</table>\'.n : \'<br style=\"clear: both;\" /></div>\'.n;\n\nif ($numPages > 1 && $showpagelinks) {\n	$next = ($numPages > 1 && $thumbpage != $numPages);\n	$back = ($numPages > 1 && $thumbpage > 1);\n	$output[] = \'<ul id=\"rssThumbNav\">\'.n;\n	$output[] = ($back) ? \'<li class=\"left\"><a href=\"?tpg=\'.($thumbpage-1).\'\">\'.$backlabel.\'</a></li>\'.n : \'\';\n	$output[] = ($next) ? \'<li class=\"right\"><a href=\"?tpg=\'.($thumbpage+1).\'\">\'.$nextlabel.\'</a></li>\'.n : \'\';\n	$output[] = \'</ul>\'.n;\n}\n\n$jpop = ($jpop) ? jsPop() : \'\';\n\nreturn ($fullontop) ? $divimg.$head.implode(\'\', $output).$jpop : $head.implode(\'\', $output).$divimg.$jpop;\n}\n\nfunction jsPop() {\nreturn <<<EOF\n<script language=\"JavaScript\" type=\"text/javascript\">\n<!--\n	// Javascript Image Gallery by Jeremy Keith\n	// http://adactio.com/articles/display.php/javascript_image_gallery\n	function showPic (whichpic) {\n		if (document.getElementById) {\n			document.getElementById(\'placeholder\').src = whichpic.href;\n			if (whichpic.title) {\n				 var rssText = whichpic.title;\n				 txtt = rssText.substring(rssText.indexOf(\'|\') + 1, rssText.length);\n				 altt = rssText.substring(0,rssText.indexOf(\'|\'));\n				 if (document.getElementById(\'jpopcap\')) document.getElementById(\'jpopcap\').childNodes[0].nodeValue = txtt;\n				 if (document.getElementById(\'jpopalt\')) document.getElementById(\'jpopalt\').childNodes[0].nodeValue = altt;\n			} else {\n				 if (document.getElementById(\'jpopcap\')) document.getElementById(\'jpopcap\').childNodes[0].nodeValue = whichpic.childNodes[0].nodeValue;\n				 if (document.getElementById(\'jpopalt\')) document.getElementById(\'jpopalt\').childNodes[0].nodeValue = whichpic.childNodes[0].nodeValue;\n			}\n			return false;\n		} else {\n			return true;\n		}\n	}\n	-->\n	</script>\nEOF;\n}\n\nif (gps(\'file\') == \'thumbpop\') {\n$id = $_GET[\"pic\"];\nif (!$id) { return; }\nglobal $pfr,$img_dir;\n$get = safe_row(\"*\",\"txp_image\",\"id=\'$id\'\");\nextract($get);\n\necho <<<EOF\n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n  <head>\n    <title>\nEOF;\n			echo $alt;\necho <<<EOF\n		</title>\n		<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n		<style type=\"text/css\" media=\"screen\">\n			<!--\n			p { font: .8em Verdana, sans-serif; text-align: center; }\n			img { padding: 2px; border: 1px solid #555; }\n			-->\n		</style>\n  </head>\n  <body>\nEOF;\n		echo \'<img src=\"\'  . $pfr.$img_dir.\'/\' . $id . $ext . \'\" alt=\"\'.$alt.\'\" /><p>\' . $caption .\'</p>\';\necho <<<EOF\n  </body>\n</html>\n\nEOF;\nexit;\n}\n','c9ac484c737aa404f97a1f4c14263efe',0,5,0),('rah_metas',1,'Jukka Svahn','http://rahforum.biz','1.3','Outputs simple metas and prevents double content','	<h1>rah_metas</h1>\n\n	<p>A tiny <abbr title=\"Search engine optimization\"><span class=\"caps\">SEO</span></abbr>- and meta-tool for <a href=\"http://www.textpattern.com\">Textpattern <span class=\"caps\">CMS</span>.</a> Build descriptions, simple meta info, rel links and prevent double content.</p>\n\n	<ul>\n		<li>Version: 1.3</li>\n		<li>Updated: 2010/05/23 9:30 AM <span class=\"caps\">UTC</span></li>\n	</ul>\n\n	<h3>Table of Contents</h3>\n\n	<ul>\n		<li><a href=\"#intro-and-description\">Intro and description</a></li>\n		<li><a href=\"#list-of-features\">List of features</a></li>\n		<li><a href=\"#requirements\">Requirements</a></li>\n		<li><a href=\"#installation-and-usage\">Installation and usage</a></li>\n		<li><a href=\"#attributes\">Attributes</a></li>\n		<li><a href=\"#example\">Examples</a></li>\n		<li><a href=\"#changelog\">Changelog</a></li>\n		<li><a href=\"#known-issues\">Known issues</a></li>\n		<li><a href=\"#thanks-to\">Thanks to</a></li>\n	</ul>\n\n	<h3 id=\"intro-and-description\">Intro and description</h3>\n\n	<p>A Textpattern plugin used for <abbr title=\"Search engine optimization\"><span class=\"caps\">SEO</span></abbr>. The plugin includes basic <span class=\"caps\">SEO</span> tools, from semi-automatic metainformation generation to useful redirections that prevent double content as rah_metas is also able redirect requested messy urls to cleans, leaving no space for the double content fault.</p>\n\n	<h3 id=\"list-of-features\">List of features</h3>\n\n	<ul>\n		<li><strong>Outputs automatic metadescriptions</strong> from article&#8217;s body, excerpt or custom field.</li>\n		<li><strong>Limits and customizes the automatic metadescription</strong> by word or character limit, strips all <span class=\"caps\">XHTML</span> and invalid characters.</li>\n		<li><strong>Redirects messy urls to clean ones, if cleans are in use</strong>. In example, <code>?id=xx</code> and <code>?s=xx</code> would be redirect to the correct place, preventing possible double content.</li>\n		<li><strong>Outputs other useful meta</strong> as author, description and language.</li>\n	</ul>\n\n	<h3 id=\"requirements\">Requirements</h3>\n\n	<p>Minimum requirements:</p>\n\n	<ul>\n		<li><span class=\"caps\">PHP</span> 4.4.0+</li>\n		<li>Textpattern 4.0.4+</li>\n	</ul>\n\n	<p>Recommended:</p>\n\n	<ul>\n		<li><span class=\"caps\">PHP</span> 5.1.2+</li>\n		<li>Textpattern 4.0.8+</li>\n	</ul>\n\n	<h3 id=\"installation-and-usage\">Installation and usage</h3>\n\n	<p>The general behavior stands: paste plugin code to the plugin installer textarea and run the automatic setup. Then just activate the plugin and you are ready to use new tags that plugin includes like others.</p>\n\n	<p>For usage, basically just put <code>&lt;txp:rah_metas /&gt;</code>-tag with wanted attributes to inside your site&#8217;s <code>&lt;head&gt;</code>-tags. As the plugin&#8217;s tag outputs metainformation, and meta-tags, it shouldn&#8217;t be used outside <code>&lt;head&gt;</code>-tags.</p>\n\n	<h3 id=\"attributes\">Attributes</h3>\n\n	<p>The tag is <code>&lt;txp:rah_metas /&gt;</code> and attributes for it follow. Default value <code>&quot;&quot;</code> means that the attribute is unset and defaultly non-used.</p>\n\n	<p><strong>imagetoolbar</strong><br />\nTo block an browser&#8217;s imagetoolbar. Allowed attributes <code>true</code> or <code>false</code>.<br />\nExample: <code>imagetoolbar=&quot;false&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>language</strong><br />\nLanguage used by the site, in example: <code>fi, en, de, se</code>.<br />\nExample: <code>language=&quot;en&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>robots</strong><br />\nHow should robots navigate. Valid values are <code>index, noindex, follow, nofollow</code> that can be compined.<br />\nExample: <code>robots=&quot;index, follow&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>author</strong><br />\nAuthor name that you wan&#8217;t to show as page&#8217;s author. Usually you, company or the website&#8217;s name.<br />\nExample: <code>author=&quot;John Doe&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>useauthor</strong><br />\nIf selected and filled, <code>&lt;txp:author /&gt;</code> is used for the author-meta, and <code>author</code>-attribute will be overrided, when viewing an induvidual article.<br />\nExample: <code>useauthor=&quot;1&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>copyright</strong><br />\nOutputs copyright-meta. Used for the content.<br />\nExample: <code>copyright=&quot;Copyrihts &amp;copy; 2007 John Doe&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<h4>Description related attributes</h4>\n\n	<p><strong>description</strong><br />\nA default meta description that will be used in article list context, or if there isn&#8217;t an article description to show and <code>description_replacement</code> is set on.<br />\nExample: <code>description=&quot;Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce at dui eget est congue aliquet. Quisque sed nunc&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>description_from</strong><br />\nWhich field is used for the automatic meta description. The attribute takes comma seperated list of fields. The first field in the list that isn&#8217;t empty is used as the meta description. Available values: <code>body</code>, <code>excerpt</code> or <code>custom field&#39;s name</code>. If the attribute is empty, then automatic description isn&#8217;t used.<br />\nExample: <code>description_from=&quot;body,excerpt,metadescription&quot;</code>  Default: <code>&quot;body,excerpt&quot;</code></p>\n\n	<p><strong>words</strong><br />\nLimits the amount of words that are shown in the automatic meta description.<br />\nExample: <code>words=&quot;15&quot;</code> Default: <code>&quot;25&quot;</code></p>\n\n	<p><strong>maxchars</strong><br />\nThe maximum number of characters in the generated automatic meta description.<br />\nExample: <code>maxchars=&quot;170&quot;</code> Default: <code>&quot;250&quot;</code></p>\n\n	<p><strong>description_trail</strong><br />\nEnding trail used in the end of the automatic metadescription. Trail is only shown if the description is longer than the limit set by <code>maxchars</code> and <code>words</code>.<br />\nExample: <code>description_trail=&quot;&quot;</code> Default:  <code>&quot;&amp;hellip;&quot;</code></p>\n\n	<p><strong>description_replacement</strong><br />\nIf set on (<code>1</code>) and there isn&#8217;t automatic description available, use <code>description</code> attribute instead. By default this feature is not used.<br />\nExample: <code>description_replacement=&quot;1&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>escape</strong><br />\nIf set to <code>1</code>, will escape raw Textile from description. Default is unset, and the feature is not used. Usually this feature isn&#8217;t required, but it might be good if you have description in a custom field and you are using Textile there. Textile in custom fields isn&#8217;t by default genenrated by Textpattern.<br />\nExample: <code>escape=&quot;1&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<h4>Keyword related attributes</h4>\n\n	<p><strong>keywords</strong><br />\nDefault keywords that will be used as keyword meta in article list context, or if there isn&#8217;t any keywords defined for article and <code>keywords_replacement</code> attribute is set on.<br />\nExample: <code>keywords=&quot;life, Doe, cat, dog&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>keywords_from</strong><br />\nWhich field is used for the keyword meta. The attribute takes comma seperated list of fields. The first field in the list that isn&#8217;t empty is used as the keywords. Available values, any article field: <code>keywords</code>, <code>body</code>, <code>excerpt</code> or <code>custom field&#39;s name</code>. If empty, the feature isn&#8217;t used.<br />\nExample: <code>keywords_from=&quot;keywords,excerpt&quot;</code>  Default: <code>&quot;keywords&quot;</code></p>\n\n	<p><strong>keywords_replacement</strong><br />\nIf there isn&#8217;t keywords available for an article, use default defined in <code>keywords</code> attribute instead.<br />\nExample: <code>keywords_replacement=&quot;1&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>keywords_limit</strong><br />\nLimits the words used in the keywords. Takes even number.<br />\nExample: <code>keywords_limit=&quot;5&quot;</code> Default: <code>&quot;25&quot;</code></p>\n\n	<h4>Redirect related attributes</h4>\n\n	<p><strong>messy_to_clean_redirect</strong><br />\nUse messy to clean redirect. Redirects messy requrests to clean urls. Use this only if you use clean urls. With messy urls this only causes eternal loop.<br />\nExample: <code>messy_to_clean_redirect=&quot;1&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>redirect_code</strong><br />\nThe code of redirection, value should be <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html\">three numeric stannard status code protocol.</a><br />\nExample: <code>redirect_code=&quot;302&quot;</code> Default: <code>&quot;301&quot;</code></p>\n\n	<h4>Rel link related attributes</h4>\n\n	<p><strong>relnext</strong><br />\nUse rel link to point next page&#8217;s location to the browser. <code>relnext</code> attribute&#8217;s value is used as <code>&lt;link rel=&quot;next&quot; /&gt;</code> tag&#8217;s <code>title</code>. Ideal values are <code>Next</code>, <code>Go to next</code> and so on. The attribute, <code>relnext</code>, adds a next rel link meta that points to the next section page or article by posting date. If attribute is used (filled) then used, if unset (empty) then not.<br />\nExample: <code>relnext=&quot;Next&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>relprev</strong><br />\nUse rel link to point previous page&#8217;s location to the browser. <code>relprev</code> attribute&#8217;s value is used as <code>&lt;link rel=&quot;prev&quot; /&gt;</code> tag&#8217;s <code>title</code>. Ideal values are <code>Previous</code>, <code>Go to prev</code> and so on. The attribute, <code>relprev</code>, adds a next rel link meta that points to the previous section page or article by posting date. If attribute is used (filled) then used, if unset (empty) then not.<br />\nExample: <code>relprev=&quot;Previous&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>prev_url</strong><br />\nManually defines relative prev url. Value should be a <span class=\"caps\">URL</span> address. The <span class=\"caps\">URL</span> is only used if automatic <span class=\"caps\">URL</span> isn&#8217;t found.<br />\nExample: <code>prev_url=&quot;http://www.example.com/path/to/id&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<p><strong>next_url</strong><br />\nManually defines relative next url. Value should be a <span class=\"caps\">URL</span> address. The <span class=\"caps\">URL</span> is only used if automatic <span class=\"caps\">URL</span> isn&#8217;t found.<br />\nExample: <code>prev_url=&quot;http://www.example.com/path/to/id&quot;</code> Default: <code>&quot;&quot;</code></p>\n\n	<h3 id=\"example\">Examples</h3>\n\n	<p><strong>#1: Basic usage</strong></p>\n\n<pre><code>&lt;txp:rah_metas keywords=&quot;dog, cat, house&quot; description=&quot;Lorem lipsum&quot; maxchars=&quot;170&quot; words=&quot;15&quot; /&gt;\n</code></pre>\n\n	<p><strong>#2: Using content preferring.</strong> First look at the custom field, then main (excerpt, body) fields.</p>\n\n<pre><code>&lt;txp:rah_metas description_from=&quot;MyCustomFieldName&quot; prefercontent=&quot;1&quot; /&gt;\n</code></pre>\n\n	<p><strong>#3: Use rah_metas tag inside <a href=\"http://textpattern.net/wiki/index.php?title=article_custom\">article_custom</a> block</strong></p>\n\n	<p>If rah_metas is placed directly inside article_custom (or article) tag, it can be used to pull the meta data from specific article.</p>\n\n<pre><code>&lt;txp:article_custom id=&quot;5&quot;&gt;\n	&lt;txp:rah_metas /&gt;\n&lt;/txp:article_custom&gt;\n</code></pre>\n\n	<p>In the code above, we took the meta data from the article where the ID is 5.</p>\n\n	<h3 id=\"changelog\">Changelog</h3>\n\n	<p><strong>Version 1.3</strong></p>\n\n	<ul>\n		<li>Now <code>description_from</code> and <code>keywords_from</code> take comma seperated list of fields. The first field in the list that isn&#8217;t empty is used as keywords or description.</li>\n		<li>Removed attribute <code>prefercontent</code>. Using the attribute will throw notice in testing or debugging mode.</li>\n	</ul>\n\n	<p><strong>Version 1.2</strong></p>\n\n	<ul>\n		<li>Now the <code>&lt;txp:rah_metas/&gt;</code> tag can be also used <em>directly inside</em> <code>&lt;txp:article_custom/&gt;</code> and <code>&lt;txp:article/&gt;</code> blocks. That means that the tag now works in article lists. You just have to point it to the article. See example number 3.</li>\n		<li>Now <em>any</em> article field can be used in <code>description_from</code> and <code>keywords_from</code> attributes. Even title, authorid, override_form or status.</li>\n		<li>Now dublicate keyword &#8220;uniqueing&#8221; is done with <code>array_unique()</code>.</li>\n		<li>Fixed keywords code escaping.</li>\n	</ul>\n\n	<p><strong>Version 1.1</strong></p>\n\n	<ul>\n		<li>Added: attribute <code>keywords_limit</code>.</li>\n		<li>Added: removes doublicated words from keywords.</li>\n		<li>Added: list view&#8217;s description is effected by word and character limits.</li>\n		<li>Fixed double <code>&quot;=&quot;</code> define bug.</li>\n		<li>Now <code>escape</code> attribute effects also body and expert, not only custom fields.</li>\n		<li>Now keywords are escaped, striped for tags and parsed.</li>\n		<li>Counts white space into chars.</li>\n		<li>Removed imagetoolbar attribute validation.</li>\n	</ul>\n\n	<p><strong>Version 1.0.5</strong></p>\n\n	<ul>\n		<li>Added attribute:  <code>escape</code>.</li>\n		<li>Rebuild description&#8217;s word and chars counting: now always counts correctly: doesn&#8217;t ever cut words.</li>\n		<li>Optimized parsing and speed: plugin is around 20% faster than before.</li>\n		<li>Removes <code>&amp;#8230;</code> from end of the description if trails are used and description is cut from context and shortened.</li>\n	</ul>\n\n	<p><strong>Version 1.0.4</strong></p>\n\n	<ul>\n		<li>Added attribute:  <code>relnext</code>.</li>\n		<li>Added attribute: <code>relprev</code>.</li>\n		<li>Minified amount of used globals by one.</li>\n	</ul>\n\n	<p><strong>Version 1.0.3</strong></p>\n\n	<ul>\n		<li>Fixed last words truncate bug.</li>\n	</ul>\n\n	<p><strong>Version 1.0.2</strong></p>\n\n	<ul>\n		<li>Fixed some typos in documention.</li>\n		<li>Now <code>prefercontent</code> also works with custom_fields.</li>\n	</ul>\n\n	<p><strong>Version 1.0.1</strong></p>\n\n	<ul>\n		<li>Debugged version 1.0: status now stable.</li>\n		<li>Fixed a bug: now whitespace is stripped from beginning and end of the description content.</li>\n	</ul>\n\n	<p><strong>Version 1.0</strong></p>\n\n	<ul>\n		<li>Improved documentation.</li>\n		<li>Little speed improvement.</li>\n		<li>Removed <code>charset</code>-attribute, it ain&#8217;t needed as Textpattern sends charset via headers &#8211; and it must not differ.</li>\n		<li>Merged <code>customfieldexcerpt</code>-attribute with <code>description_from</code>.</li>\n		<li>Included redirecting functions that prevent double content when using clean urls.</li>\n		<li>Validates <code>imagetoolbar</code>-attribute to false or true.</li>\n		<li>Added attribute: <code>description_replacement</code>.</li>\n		<li>Added attribute: <code>keywords_replacement</code>.</li>\n		<li>Added attribute: <code>description_from</code></li>\n		<li>Added attribute: <code>messy_to_clean_redirect</code>.</li>\n		<li>Added attribute: <code>redirect_code</code>.</li>\n		<li>Added attribute: <code>description_trail</code>.</li>\n		<li>Added invalid charasters removing for custom fields.</li>\n		<li>Removed Textile removing from body and excerpt, that was meant to remove Textile + <span class=\"caps\">XHTML</span> bugs caused by user&#8217;s invalid article code, and used instead body_html, and just stripped <span class=\"caps\">HTML</span>: it&#8217;s faster.</li>\n		<li>Some users wanted to be able input invalid characters to description: now it is possible, if you turn Textile off: why should we validate meta description, if article&#8217;s body itself is invalid, because writer doesn&#8217;t use valid <span class=\"caps\">HTML</span> special characters.</li>\n	</ul>\n\n	<p><strong>Version minor 0.9.2</strong></p>\n\n	<ul>\n		<li>One bug fix, created by little one chars typo in the code.</li>\n	</ul>\n\n	<p><strong>Version minor 0.9.1</strong></p>\n\n	<ul>\n		<li>Removed a debugging error, caused by undefined variable if there were no description.</li>\n	</ul>\n\n	<p><strong>Version 0.9</strong></p>\n\n	<ul>\n		<li>Added attribute: <code>copyright</code>.</li>\n		<li>Added attribute: <code>useauthor</code>.</li>\n		<li>Added attribute: <code>customfieldkeywords</code>.</li>\n		<li>Added attribute: <code>customfieldexcerpt</code>.</li>\n	</ul>\n\n	<p><strong>Version 0.8</strong></p>\n\n	<ul>\n		<li>Added Textile remover: removes Textile completely from description</li>\n		<li>Cleaned up the code</li>\n	</ul>\n\n	<p><strong>Version 0.7</strong></p>\n\n	<ul>\n		<li>Fixed bug that appears if single article has no body or excerpt. Only shown in debugging.</li>\n	</ul>\n\n	<p><strong>Version 0.6</strong></p>\n\n	<ul>\n		<li>Fixed a code-removing bug</li>\n		<li>Now removes all code from automatic metadescription</li>\n	</ul>\n\n	<p><strong>Version 0.5</strong></p>\n\n	<ul>\n		<li>Finished bug-testing</li>\n	</ul>\n\n	<p><strong>Version 0.4</strong></p>\n\n	<ul>\n		<li>Add missing variable</li>\n	</ul>\n\n	<p><strong>Version 0.3</strong></p>\n\n	<ul>\n		<li>Compined two seperated functions</li>\n		<li>Improved the code by fixing globals</li>\n	</ul>\n\n	<p><strong>Version 0.2</strong></p>\n\n	<ul>\n		<li>Replaced automatic-medescription&#8217;s ending points <code>&amp;#8230;</code> with <code>&amp;hellip;</code></li>\n		<li>Added new attribute: <code>imagetoolbar</code></li>\n	</ul>\n\n	<p><strong>Version 0.1</strong></p>\n\n	<ul>\n		<li>First release</li>\n	</ul>\n\n	<h3 id=\"known-issues\">Known issues</h3>\n\n	<p>Redirects might not always work on old fast-cgi (requires clarifation), but on other systems fine.</p>\n\n	<h3 id=\"thanks-to\">Thanks to</h3>\n\n	<ul>\n		<li>All folks that thanked me by making this plugin available.</li>\n		<li>rolograaf and pat64 for great ideas of keywords.</li>\n		<li>fuls, strawberryfusion, jim_01 and ian_ep for reporting me some bugs.</li>\n		<li>maniqui for the ideas.</li>\n		<li>And all the other great Textpatternists.</li>\n	</ul>','	##################\r\n	#\r\n	#	rah_metas-plugin for Textpattern\r\n	#	version 1.3\r\n	#	by Jukka Svahn\r\n	#	http://rahforum.biz\r\n	#\r\n	###################\r\n\r\n	function rah_metas($atts=array()) {\r\n		extract(lAtts(rah_metas_atts(),$atts));\r\n\r\n		global $is_article_list,$thisarticle;\r\n		$out = array();\r\n		\r\n		$author = ($useauthor && !empty($thisarticle)) ? author(array()) : $author;\r\n		$description = rah_metas_description($atts);\r\n		$keywords = rah_metas_keywords($atts);\r\n		\r\n		if($is_article_list == true) {\r\n			if($relprev) $prev_url = older(array(),false);\r\n			if($relnext) $next_url = newer(array(),false);\r\n		} else {\r\n			if($relprev) $prev_url = link_to_prev(array(),false);\r\n			if($relnext) $next_url = link_to_next(array(),false);\r\n		}\r\n		\r\n		if($imagetoolbar)\r\n			$out[] = \'<meta http-equiv=\"imagetoolbar\" content=\"\'.$imagetoolbar.\'\" />\';\r\n		if($language)\r\n			$out[] = \'<meta http-equiv=\"content-language\" content=\"\'.$language.\'\" />\';\r\n		if($copyright) \r\n			$out[] = \'<meta name=\"copyright\" content=\"\'.$copyright.\'\" />\';\r\n		if($robots) \r\n			$out[] = \'<meta name=\"robots\" content=\"\'.$robots.\'\" />\';\r\n		if($author)\r\n			$out[] = \'<meta name=\"author\" content=\"\'.$author.\'\" />\';\r\n		if($keywords) \r\n			$out[] = \'<meta name=\"keywords\" content=\"\'.$keywords.\'\" />\';\r\n		if($description)\r\n			$out[] = \'<meta name=\"description\" content=\"\'.$description.\'\" />\';\r\n		if($prev_url)\r\n			$out[] = \'<link rel=\"prev\" href=\"\'.$prev_url.\'\" title=\"\'.$relprev.\'\" />\';\r\n		if($next_url)\r\n			$out[] = \'<link rel=\"next\" href=\"\'.$next_url.\'\" title=\"\'.$relnext.\'\" />\';\r\n		\r\n		if($messy_to_clean_redirect) {\r\n			if(gps(\'s\')) \r\n				header(\'Location: \'.pagelinkurl(array(\'s\' => gps(\'s\'))),TRUE,$redirect_code);\r\n			if(is_numeric(gps(\'id\'))) \r\n				header(\'Location: \'.permlink(array(\'id\' => gps(\'id\'))),TRUE,$redirect_code);\r\n		}\r\n		\r\n		return implode(n,$out);\r\n	}\r\n\r\n	function rah_metas_atts() {\r\n		return \r\n			array(\r\n				\'language\' => \'\',\r\n				\'keywords\' => \'\',\r\n				\'keywords_from\' => \'keywords\',\r\n				\'keywords_replacement\' => \'\',\r\n				\'keywords_limit\' => \'25\',\r\n				\'description\' => \'\',\r\n				\'description_from\' => \'body,excerpt\',\r\n				\'description_trail\' => \'&hellip;\',\r\n				\'escape\' => \'\',\r\n				\'maxchars\' => \'250\',\r\n				\'words\' => \'25\',\r\n				\'description_replacement\' => \'\',\r\n				\'author\' => \'\',\r\n				\'useauthor\' => \'\',\r\n				\'robots\' => \'\',\r\n				\'imagetoolbar\' => \'\',\r\n				\'copyright\' => \'\',\r\n				\'messy_to_clean_redirect\' => \'\',\r\n				\'redirect_code\' => \'301\',\r\n				\'relnext\' => \'\',\r\n				\'relprev\' => \'\',\r\n				\'prev_url\' => \'\',\r\n				\'next_url\' => \'\',\r\n			)\r\n		;\r\n	}\r\n\r\n	function rah_metas_keywords($atts) {\r\n		extract(lAtts(rah_metas_atts(),$atts));\r\n		\r\n		$out = array();\r\n		$count = 0;\r\n		\r\n		$content = \r\n			rah_metas_content(\r\n				$keywords_from,\r\n				$keywords_replacement,\r\n				$keywords\r\n			);\r\n		\r\n		if($content) {\r\n			$content = rah_metas_strip($content);\r\n			$keywords = explode(\',\',$content);\r\n			$keywords = array_unique($keywords);\r\n			\r\n			foreach($keywords as $keyword) {\r\n				$keyword = trim($keyword);\r\n				if(!empty($keyword)) {\r\n					$count++;\r\n					$out[] = $keyword;\r\n				}\r\n				if($keywords_limit <= $count)\r\n					return implode(\', \',$out);\r\n			}\r\n			\r\n			$content = implode(\', \',$out);\r\n		}\r\n		return $content;\r\n	}\r\n\r\n	function rah_metas_description($atts) {\r\n		extract(lAtts(rah_metas_atts(),$atts));\r\n\r\n		$content = \r\n			rah_metas_content(\r\n				$description_from,\r\n				$description_replacement,\r\n				$description\r\n			);\r\n		\r\n		if($content) {\r\n			if($escape) \r\n				$content = rah_metas_textile($content);\r\n			$content = rah_metas_strip($content);\r\n			$word = array();\r\n			$count_char = 0;\r\n			$count_word = 0;\r\n			$tokens = explode(\' \',$content);\r\n			foreach($tokens as $token) {\r\n				$token = trim($token);\r\n				if(empty($token))\r\n					continue;\r\n				if($count_char <= $maxchars && $count_word <= $words)\r\n					$word[] = $token;\r\n				else \r\n					return rah_metas_trail($word).$description_trail;\r\n				$count_char = strlen($token)+$count_char+1;\r\n				$count_word++;\r\n			}\r\n			$content = implode(\' \',$word);\r\n		}\r\n		return $content;\r\n	}\r\n\r\n	function rah_metas_content($string=\'\',$replacement=\'\',$default=\'\') {\r\n		\r\n		global $thisarticle;\r\n		\r\n		if(empty($thisarticle))\r\n			return $default;\r\n		\r\n		$array = \r\n			explode(\',\',$string);\r\n		\r\n		foreach($array as $field) {\r\n			$field = trim($field);\r\n			if(!empty($field) && isset($thisarticle[$field]) && !empty($thisarticle[$field]))\r\n				return $thisarticle[$field];\r\n		}\r\n		\r\n		if($replacement)\r\n			return $default;\r\n	}\r\n\r\n	function rah_metas_trail($out=array()) {\r\n		$content = implode(\' \',$out);\r\n		if(\r\n			substr($content, -7, 7) == \'&#8230;\'\r\n		)\r\n			$content = substr($content,0,-7);\r\n		return $content;\r\n	}\r\n\r\n	function rah_metas_strip($out=\'\') {\r\n		return \r\n			trim(\r\n				str_replace(\r\n					array(\"\\n\",\"\\t\",\'\"\',\'>\',\'<\'),\r\n					array(\' \',\'\',\'&quot;\',\'&gt;\',\'&lt;\'),\r\n					strip_tags(\r\n						trim(\r\n							parse($out)\r\n						)\r\n					)\r\n				)\r\n			)\r\n		;\r\n	}\r\n\r\n	function rah_metas_textile($out=\'\') {\r\n		@include_once(txpath.\'/lib/classTextile.php\');\r\n		$textile = new Textile();\r\n		return $textile->TextileThis($out);\r\n	}','	##################\r\n	#\r\n	#	rah_metas-plugin for Textpattern\r\n	#	version 1.3\r\n	#	by Jukka Svahn\r\n	#	http://rahforum.biz\r\n	#\r\n	###################\r\n\r\n	function rah_metas($atts=array()) {\r\n		extract(lAtts(rah_metas_atts(),$atts));\r\n\r\n		global $is_article_list,$thisarticle;\r\n		$out = array();\r\n		\r\n		$author = ($useauthor && !empty($thisarticle)) ? author(array()) : $author;\r\n		$description = rah_metas_description($atts);\r\n		$keywords = rah_metas_keywords($atts);\r\n		\r\n		if($is_article_list == true) {\r\n			if($relprev) $prev_url = older(array(),false);\r\n			if($relnext) $next_url = newer(array(),false);\r\n		} else {\r\n			if($relprev) $prev_url = link_to_prev(array(),false);\r\n			if($relnext) $next_url = link_to_next(array(),false);\r\n		}\r\n		\r\n		if($imagetoolbar)\r\n			$out[] = \'<meta http-equiv=\"imagetoolbar\" content=\"\'.$imagetoolbar.\'\" />\';\r\n		if($language)\r\n			$out[] = \'<meta http-equiv=\"content-language\" content=\"\'.$language.\'\" />\';\r\n		if($copyright) \r\n			$out[] = \'<meta name=\"copyright\" content=\"\'.$copyright.\'\" />\';\r\n		if($robots) \r\n			$out[] = \'<meta name=\"robots\" content=\"\'.$robots.\'\" />\';\r\n		if($author)\r\n			$out[] = \'<meta name=\"author\" content=\"\'.$author.\'\" />\';\r\n		if($keywords) \r\n			$out[] = \'<meta name=\"keywords\" content=\"\'.$keywords.\'\" />\';\r\n		if($description)\r\n			$out[] = \'<meta name=\"description\" content=\"\'.$description.\'\" />\';\r\n		if($prev_url)\r\n			$out[] = \'<link rel=\"prev\" href=\"\'.$prev_url.\'\" title=\"\'.$relprev.\'\" />\';\r\n		if($next_url)\r\n			$out[] = \'<link rel=\"next\" href=\"\'.$next_url.\'\" title=\"\'.$relnext.\'\" />\';\r\n		\r\n		if($messy_to_clean_redirect) {\r\n			if(gps(\'s\')) \r\n				header(\'Location: \'.pagelinkurl(array(\'s\' => gps(\'s\'))),TRUE,$redirect_code);\r\n			if(is_numeric(gps(\'id\'))) \r\n				header(\'Location: \'.permlink(array(\'id\' => gps(\'id\'))),TRUE,$redirect_code);\r\n		}\r\n		\r\n		return implode(n,$out);\r\n	}\r\n\r\n	function rah_metas_atts() {\r\n		return \r\n			array(\r\n				\'language\' => \'\',\r\n				\'keywords\' => \'\',\r\n				\'keywords_from\' => \'keywords\',\r\n				\'keywords_replacement\' => \'\',\r\n				\'keywords_limit\' => \'25\',\r\n				\'description\' => \'\',\r\n				\'description_from\' => \'body,excerpt\',\r\n				\'description_trail\' => \'&hellip;\',\r\n				\'escape\' => \'\',\r\n				\'maxchars\' => \'250\',\r\n				\'words\' => \'25\',\r\n				\'description_replacement\' => \'\',\r\n				\'author\' => \'\',\r\n				\'useauthor\' => \'\',\r\n				\'robots\' => \'\',\r\n				\'imagetoolbar\' => \'\',\r\n				\'copyright\' => \'\',\r\n				\'messy_to_clean_redirect\' => \'\',\r\n				\'redirect_code\' => \'301\',\r\n				\'relnext\' => \'\',\r\n				\'relprev\' => \'\',\r\n				\'prev_url\' => \'\',\r\n				\'next_url\' => \'\',\r\n			)\r\n		;\r\n	}\r\n\r\n	function rah_metas_keywords($atts) {\r\n		extract(lAtts(rah_metas_atts(),$atts));\r\n		\r\n		$out = array();\r\n		$count = 0;\r\n		\r\n		$content = \r\n			rah_metas_content(\r\n				$keywords_from,\r\n				$keywords_replacement,\r\n				$keywords\r\n			);\r\n		\r\n		if($content) {\r\n			$content = rah_metas_strip($content);\r\n			$keywords = explode(\',\',$content);\r\n			$keywords = array_unique($keywords);\r\n			\r\n			foreach($keywords as $keyword) {\r\n				$keyword = trim($keyword);\r\n				if(!empty($keyword)) {\r\n					$count++;\r\n					$out[] = $keyword;\r\n				}\r\n				if($keywords_limit <= $count)\r\n					return implode(\', \',$out);\r\n			}\r\n			\r\n			$content = implode(\', \',$out);\r\n		}\r\n		return $content;\r\n	}\r\n\r\n	function rah_metas_description($atts) {\r\n		extract(lAtts(rah_metas_atts(),$atts));\r\n\r\n		$content = \r\n			rah_metas_content(\r\n				$description_from,\r\n				$description_replacement,\r\n				$description\r\n			);\r\n		\r\n		if($content) {\r\n			if($escape) \r\n				$content = rah_metas_textile($content);\r\n			$content = rah_metas_strip($content);\r\n			$word = array();\r\n			$count_char = 0;\r\n			$count_word = 0;\r\n			$tokens = explode(\' \',$content);\r\n			foreach($tokens as $token) {\r\n				$token = trim($token);\r\n				if(empty($token))\r\n					continue;\r\n				if($count_char <= $maxchars && $count_word <= $words)\r\n					$word[] = $token;\r\n				else \r\n					return rah_metas_trail($word).$description_trail;\r\n				$count_char = strlen($token)+$count_char+1;\r\n				$count_word++;\r\n			}\r\n			$content = implode(\' \',$word);\r\n		}\r\n		return $content;\r\n	}\r\n\r\n	function rah_metas_content($string=\'\',$replacement=\'\',$default=\'\') {\r\n		\r\n		global $thisarticle;\r\n		\r\n		if(empty($thisarticle))\r\n			return $default;\r\n		\r\n		$array = \r\n			explode(\',\',$string);\r\n		\r\n		foreach($array as $field) {\r\n			$field = trim($field);\r\n			if(!empty($field) && isset($thisarticle[$field]) && !empty($thisarticle[$field]))\r\n				return $thisarticle[$field];\r\n		}\r\n		\r\n		if($replacement)\r\n			return $default;\r\n	}\r\n\r\n	function rah_metas_trail($out=array()) {\r\n		$content = implode(\' \',$out);\r\n		if(\r\n			substr($content, -7, 7) == \'&#8230;\'\r\n		)\r\n			$content = substr($content,0,-7);\r\n		return $content;\r\n	}\r\n\r\n	function rah_metas_strip($out=\'\') {\r\n		return \r\n			trim(\r\n				str_replace(\r\n					array(\"\\n\",\"\\t\",\'\"\',\'>\',\'<\'),\r\n					array(\' \',\'\',\'&quot;\',\'&gt;\',\'&lt;\'),\r\n					strip_tags(\r\n						trim(\r\n							parse($out)\r\n						)\r\n					)\r\n				)\r\n			)\r\n		;\r\n	}\r\n\r\n	function rah_metas_textile($out=\'\') {\r\n		@include_once(txpath.\'/lib/classTextile.php\');\r\n		$textile = new Textile();\r\n		return $textile->TextileThis($out);\r\n	}','0202ab7d31f17b830482e3f65d622950',0,5,0),('mka_ical',0,'Martin Kozianka','http://kozianka-online.de/','0.6.1','Display events from an ical-File (Google Calendar, ...)','<div id=\"txp_mka\">\n\n<h1>mka_ical - Help</h1>\n\n<p style=\"color:red;\"><strong>\nThe help section is not complete so if you have any questions please write a comment.<br/>\n<a href=\"http://kozianka-online.de/mka_ical\">http://kozianka-online.de/mka_ical</a>\n</strong></p>\n\n\n<p>With the mka_ical plugin it is possible to display Events from iCal URL or File (e.g. Google Calendar).<br/>\nThe plugin makes use of SG-iCalendar by Morten Fangel (http://github.com/fangel/SG-iCalendar)</p>\n<h2>How to use</h2>\n\n<h3>Example 1 (Using a public Google Calendar)</h3>\n<pre><code class=\"block\">&lt;txp:mka_ical googlemail=&quot;YOURADDRESSNAME@googlemail.com&quot; /&gt;</code></pre>\n<ul>\n	<li><strong>googlemail</strong>: Your GoogleMail address.</li>\n</ul>\n<br/>\n\n\n<h3>Example 2 (Using some options)</h3>\n<pre><code class=\"block\">&lt;txp:mka_ical url=&quot;http://url.of.ics.file/calendar.ics&quot;\n	pastevents=&quot;1&quot;  limit=&quot;0&quot;\n	imgfolder=&quot;images/termine/&quot; defaultimage=&quot;images/termine/none.gif&quot; /&gt;</code></pre>\n<ul>\n	<li><strong>url</strong>: URL of a Calendar File</li>\n	<li><strong>pastevents</strong>: [0,1] Show past events?</li>\n	<li><strong>limit</strong>: [0,1,2,3,4,..] Show only X events</li>\n	<li><strong>imgfolder</strong>: Where are the images?</li>\n	<li><strong>defaultimage</strong>: Path to the default image</li>\n</ul>\n<br/>\n\n<h2>Default template</h2>\n<pre><code class=\"block\">&lt;span class=\"date\"&gt;{date}&lt;/span&gt;\n&lt;span class=\"title\"&gt;{title}&lt;/span&gt;\n&lt;span class=\"description\"&gt;{description}&lt;/span&gt;\n</code></pre>\n<br/>\n\n<h2>Defining own template</h2>\n\n<h4>Embed template</h4>\n<pre><code class=\"block\">&lt;txp:mka_ical wraptag=\"\" break=\"\" googlemail=&quot;YOURADDRESSNAME@googlemail.com&quot;&gt;\n&lt;p&gt;\n  &lt;h4&gt;{date} - {title}&lt;/h4&gt;\n  &lt;img src=\"{imagesrc}\" border=\"0\" align=\"left\"/&gt;\n  &lt;p&gt;{description}&lt;/p&gt;\n&lt;/p&gt;\n&lt;/txp:mka_ical&gt;</code></pre>\n\n<h4>Using form attribute</h4>\n<pre><code class=\"block\">&lt;txp:mka_ical form=\"mka_ical_template\" googlemail=&quot;YOURADDRESSNAME@googlemail.com&quot;/&gt;</code></pre>\n<br/>\n\n<h2>Available variables</h2>\n<pre><code class=\"block\"><code>{date} - Date\n{title} - Title\n{description} - Description\n{imagesrc} - image link\n{imageid} - image id (only for images from txp categories)</code></pre>\n<br/>\n\n\n<h2>CSS Template</h2>\n<pre><code class=\"block\">ul#icalevents {\n}\n\nul#icalevents li {\n}\n\nul#icalevents li img {\n}\n\nul#icalevents li span.date {\n}\n\nul#icalevents li span.title {\n}\n\nul#icalevents li p.description {\n}\n</code></pre>\n\n<h2>Attributes</h2>\n\n<pre><code class=\"block\">\nurl (string, default: \"\", url or googlemail required)\nLink to the ICS-File\n\ngooglemail\nGoogleMail address (calendar must be public, url or googlemail required))\n\nlimit (int, default:0, optional)\nDefines how many events are shown. Defaults to 0 (means all)\n\npastevents (boolean, default: FALSE, optional)\nDisplay past events\n\ncssid (string, default: \"icalevents\", optional)\nSets the id for the event list\n\nclass\nSets the CSS-Class for the event list\n\ncachingtime (int, default: 5 (minutes), optional)\nlocal caching\n\nfmtTime (string, default: \"H:i\", optional)\nFormat String for the Time\n\nfmtDate (string, default: \"d.m.Y\", optional)\nFormat String for the date\n\nimgfolder (string, default: \"images\", optional)\nimage folder\n\nimgcat (string, default: \"\", optional)\nimage category\n\ndefaultimage (string, default: \"images/none.gif\", optional)\npath to or id of the default image\n\nwraptag (string, default: \"ul\", optional)\nWraptag-Tag\n\nbreak (string, default: \"li\", optional)\nBreak-Tag\n\nclass (string, default: \"mka_ical\", optional)\nCSS-Class for wraptag-Tag\n\ncssid (string, default: \"icalevents\", optional)\nCSS-Id for wraptag-Tag\n</code></pre>\n\n</div>\n<!-- *** BEGIN PLUGIN CSS *** -->\n<style type=\"text/css\">\n		#txp_mka code {\n			font-weight:bold;\n			font: 105%/130% \"Courier New\", courier, monospace;\n			background-color: #FFFFCC;\n		}\n		#txp_mka code.block {\n			font-weight:normal;\n			border:1px dotted #999;\n			background-color: #FFFFCC;\n			display:block;\n			margin:10px 10px 20px;\n			padding:10px;\n		}\n</style>\n<!-- *** END PLUGIN CSS *** -->\n','function mka_ical($atts, $thing = \'\') {\r\n	$time_start = microtime(true);\r\n	global $txpcfg;\r\n	extract(lAtts(array(\r\n		\'url\' => \'\',\r\n		\'cachingtime\' => 30,\r\n		\'googlemail\' => \'\',\r\n		\'limit\' => 0,\r\n		\'pastevents\' => false,\r\n		\'fmtTime\' => \'H:i\',\r\n		\'fmtDate\' => \'d.m.Y\',\r\n		\'imgfolder\' => \'\',\r\n		\'imgcat\' => \'\',	\r\n		\'defaultimage\' => \'none.gif\',\r\n		\'break\'  => \'li\',\r\n		\'class\' => __FUNCTION__,\r\n		\'cssid\' => \'icalevents\',\r\n		\'wraptag\'  => \'ul\',\r\n		\'form\'  => \'\'\r\n	), $atts));\r\n	\r\n	if (strlen($thing) > 0) {\r\n		$body = $thing;\r\n	} else if (!empty($form)) {\r\n		$body = fetch_form($form);\r\n	} else {\r\n		// Default body\r\n		$body = \'<li><span class=\"date\">{date}</span>\'\r\n				.\'<span class=\"title\">{summary}</span>\'\r\n				.\'<span class=\"description\">{description}</span></li>\';\r\n	}\r\n\r\n	// get url from googlemail-address\r\n	if (strlen($googlemail) > 0) {\r\n		$tmp = explode(\"@\", $googlemail);\r\n		$gmail = $tmp[0];\r\n		$urls[] = \"http://www.google.com/calendar/ical/\".$googlemail.\"%40googlemail.com/public/basic.ics\";\r\n	}\r\n	\r\n	// add given urls from attribute url\r\n	if (strlen($url) > 0) {\r\n		foreach (explode(\",\", $url) as $u)\r\n			$urls[] = trim($u);\r\n	}\r\n	\r\n	// no url --> Nothing to show.\r\n	if (sizeof($urls) === 0) {\r\n		return \"Error: No url given.\";\r\n	}\r\n	\r\n	// get images from folder and/or category\r\n	$show_img = false;\r\n	if ((strlen($imgcat) > 0) || (strlen($imgfolder) > 0 )) {\r\n		$images = array();\r\n		\r\n		// add images from given categories\r\n		if (strlen($imgcat) > 0) {\r\n			$images = mka_imgarrayfromcat($imgcat);	\r\n		}\r\n		\r\n		// Add images from given folder\r\n		if (file_exists($imgfolder)) {\r\n			$images = array_merge(mka_imgarrayfromfolder($imgfolder));\r\n		}\r\n\r\n		if (sizeof($images) > 0) {\r\n			$show_img = true;\r\n\r\n			// get default image\r\n			$defimg = ical_defimg($defaultimage);\r\n		}\r\n	}\r\n\r\n	\r\n	// get events from cache\r\n	$events = checkCache($urls, $cachingtime);\r\n\r\n	\r\n	// loop trough events\r\n	$i = 1;\r\n	foreach ($events as $evt) {\r\n\r\n		// is event in future or running?\r\n		if (($pastevents || $evt->end > mktime()) && ($limit == 0 || $i <= $limit )) {\r\n\r\n			// TODO :: TextileRestricted($text, $lite = 1, $noimage = 1, $rel = \'nofollow\')\r\n			$evt->sum = ical_formatText($evt->sum);\r\n			$evt->des = ical_formatText($evt->des);\r\n\r\n			$dateView = ical_getDateView($evt, $fmtDate, $fmtTime);\r\n\r\n			if ($show_img) {\r\n				$image = ical_img($evt->sum, $images, $defimg);\r\n			}\r\n\r\n			// $output[] = parse();	\r\n			$keys = array(); $vals = array();\r\n			$keys[] = \'{date}\';		$vals[] = $dateView;\r\n			$keys[] = \'{title}\';		$vals[] = $evt->sum;\r\n			$keys[] = \'{description}\';	$vals[] = $evt->des;\r\n			$keys[] = \'{imagesrc}\';		$vals[] = $image[\'src\'];\r\n			$keys[] = \'{imageid}\';		$vals[] = $image[\'id\'];\r\n\r\n			\r\n			$out[] = parse(str_replace($keys, $vals, $body));\r\n			\r\n			$i++; // count for attr limit\r\n		} // if ($evt->getEnd() > mktime() && ($limit == 0  || $i <= $limit ))\r\n\r\n	}\r\n	\r\n	$gen =  \"<!-- mka_ical - generated in \".((microtime(true)-$time_start)*1000).\"ms -->\";\r\n	// definition of doWrap\r\n	// http://www.consking.com/txp406/nav.html?textpattern/publish/taghandlers.php.html#dowrap\r\n	return doWrap($out, $wraptag, $break, $class, \'\', \'\', \'\', $cssid).$gen;\r\n	\r\n}\r\n\r\n\r\nfunction ical_img($title, $images, $defimg) {\r\n	$search = array(\" \", \".\", \"-\");\r\n	$rep = array(\"\", \"\", \"\");\r\n	$t = str_replace($search, $rep, strtolower($title));\r\n	foreach ($images as $im) {\r\n		if (strpos($t, $im[\'name\']) !== false) {\r\n			return $im;\r\n		}\r\n	}\r\n	// return default image src\r\n	return $defimg;\r\n}\r\n\r\n\r\nfunction ical_getDateView($evt, $fmtDate, $fmtTime) {\r\n	$fmtDaTi = $fmtDate.\" \".$fmtTime;\r\n	// event on one day\r\n	if (date(\"dmY\",$evt->start) == date(\"dmY\",$evt->end-1)) {\r\n		// no exact time definition\r\n		if (date(\"H:i\",$evt->start) == \"00:00\" && date(\"H:i\",$evt->end) == \"00:00\") {\r\n			$dateView = date($fmtDate, $evt->start);\r\n		}\r\n		else {\r\n			$dateView = date($fmtDaTi, $evt->start).\"-\".date($fmtTime, $evt->start + $evt->duration);\r\n		}\r\n	\r\n	}	\r\n	else {\r\n		$dateView  = date($fmtDate, $evt->start).\"-\".date($fmtDate, $evt->end-1);\r\n	}\r\n	return $dateView;\r\n}\r\n\r\nfunction mka_makearr_sql($str, $type=\'string\', $delimeter =\',\') {\r\n	$ret = array();\r\n	$arr = explode($delimeter, $str);\r\n	foreach ($arr as $el) {\r\n		if ($type == \'string\')\r\n			$ret[] = \"\'\".trim($el).\"\'\";\r\n		else \r\n			$ret[] = $el;\r\n	}\r\n	return $ret;\r\n}\r\n\r\nfunction mka_imgarrayfromcat($cats) {\r\n	$imgs = array();\r\n	\r\n	$cats = mka_makearr_sql($cats);\r\n	$clause = \'category IN (\'.implode(\",\", $cats).\')\';\r\n	$attrs = \'id, name, ext\';\r\n	$rs = safe_rows($attrs,\'txp_image\', $clause);\r\n	\r\n	$prefix = \"http://\".$GLOBALS[\'prefs\'][\"siteurl\"].\"/\".$GLOBALS[\'prefs\'][\'img_dir\'].\"/\";\r\n	\r\n	if (count($rs) != 0) {\r\n		foreach ($rs as $col) {\r\n			$col[\'src\'] = $prefix.$col[\'id\'].$col[\'ext\'];\r\n			$imgs[] = $col;	\r\n		}\r\n	}\r\n	return $imgs;\r\n}\r\n\r\nfunction mka_imgarrayfromfolder($imgfolder) {\r\n	$imgs = array();\r\n	if ($handle = @opendir($imgfolder)) {\r\n		while (($file = @readdir($handle)) !== false) {\r\n			$img = array();\r\n			$parts = explode(\".\", $file);\r\n			$img[\'ext\']  = (count($parts) > 1) ? \".\".array_pop($parts) : \'\';\r\n			$img[\'name\'] = implode(\".\", $parts);\r\n			$img[\'src\'] = \"http://\".$GLOBALS[\'prefs\'][\"siteurl\"].\"/\".$imgfolder.\"/\".$file;\r\n			if (strlen($img[\'name\']) > 0 && in_array(strtolower($img[\'ext\']), array(\".png\", \".jpg\", \".jpeg\", \".gif\"))) {\r\n				$imgs[] = $img;\r\n			}\r\n		}\r\n		closedir($handle);\r\n	}\r\n	return $imgs;\r\n}\r\n\r\n\r\nfunction ical_defimg($defimg) {\r\n	$url = \"http://\".$GLOBALS[\'prefs\'][\"siteurl\"].\"/\";\r\n	$img = array();\r\n	// is defimg id?\r\n	if (intval($defimg) !== 0) {\r\n		$id = intval($defimg);\r\n		$img = safe_row(\'id, name, ext\', \'txp_image\', \'id = \'.$id);\r\n	}\r\n	\r\n	// image with id not found?\r\n	if (sizeof($img) === 0) {\r\n		$parts = explode(\".\", basename($defimg));\r\n		$img[\'ext\']  = (count($parts) > 1) ? \".\".array_pop($parts) : \'\';\r\n		$img[\'name\'] = implode(\".\", $parts);\r\n		$img[\'src\'] = $url.$defimg;\r\n	}\r\n	else {\r\n		$img[\"src\"] = $url.$GLOBALS[\'prefs\'][\'img_dir\'].\"/\".$img[\'id\'].$img[\'ext\'];\r\n	}\r\n	return $img;\r\n}\r\n\r\nfunction ical_shorten_link($string) {\r\n	$text_word_maxlength = 55;\r\n	if(count($string) == 2) { $pre = \"\"; $url = $string[1]; }\r\n	else { $pre = $string[1]; $url = $string[2]; }\r\n	$shortened_url = $url;\r\n	if (strlen($url) > $text_word_maxlength) $shortened_url = substr($url, 0, ($text_word_maxlength/2)) . \"...\" . substr($url, - ($text_word_maxlength-3-$text_word_maxlength/2));\r\n	return $pre.\"<a href=\\\"\".$url.\"\\\">\".$shortened_url.\"</a>\";\r\n}\r\n\r\nfunction ical_formatText($string) {\r\n	$string = \' \' . $string;\r\n	$string = preg_replace_callback(\"#(^|[\\n ])([\\w]+?://.*?[^ \\\"\\n\\r\\t<]*)#is\", \"ical_shorten_link\", $string);\r\n	$string = preg_replace(\"#(^|[\\n ])((www|ftp)\\.[\\w\\-]+\\.[\\w\\-.\\~]+(?:/[^ \\\"\\t\\n\\r<]*)?)#is\", \"$1<a href=\\\"http://$2\\\">$2</a>\", $string);\r\n	$string = str_replace(\"\\n\",\"<br/>\",$string);\r\n	return $string;\r\n}\r\n function checkCache($urls, $cachingtime) { $hash = md5(implode(\",\", $urls)); $fn = \"files/mka_ical_\".$hash.\".json\"; if (file_exists($fn) && (time()-filemtime($fn) < ($cachingtime*60))) {  $cache_file = fopen($fn,\"r\"); $data = fread($cache_file, filesize($fn)); fclose($cache_file); return json_decode($data); } else {  $events = getEvents($urls); $cf = fopen($fn,\"w+\"); fwrite($cf, json_encode($events)); fclose($cf); return $events; } } function getEvents($urls) { $events = array(); $reader = new SG_iCal(); foreach($urls as $u) { $reader->setUrl($u, true); $e = $reader->getEvents(); foreach($e as $event) { $events[] = getPlainEvent($event); } }  usort($events, \"cmp_event\"); return $events; } function getPlainEvent($evt) { $plainEvent = new stdClass; $plainEvent->start = $evt->getStart(); $plainEvent->end = $evt->getEnd(); $plainEvent->duration = $evt->getDuration(); $plainEvent->sum = $evt->getSummary(); $plainEvent->des = $evt->getDescription(); $plainEvent->loc = $evt->getLocation(); return $plainEvent; } function cmp_event($a, $b) { $da = $a->start; $db = $b->start; if ($da == $db) { return 1; } return ($da < $db) ? -1 : 1; }  define(\'SG_ICALREADER_VERSION\', \'0.5\');  class SG_iCal { private $information; private $events; private $timezones;  public function __construct($url = false) {                     if( $url !== false ) { SG_iCal_Parser::Parse($url, $this); } }  public function setUrl( $url = false ) { if( $url !== false ) { SG_iCal_Parser::Parse($url, $this); } }  public function getCalendarInfo() { return $this->information; }  public function setCalendarInfo( SG_iCal_VCalendar $info ) { $this->information = $info; }  public function getTimeZoneInfo( $tzid = null ) { if( $tzid == null ) { return $this->timezones; } else { if ( !isset($this->timezones)) { return null; } foreach( $this->timezones AS $tz ) { if( $tz->getTimeZoneId() == $tzid ) { return $tz; } } return null; } }  public function addTimeZone( SG_iCal_VTimeZone $tz ) { $this->timezones[] = $tz; }  public function getEvents() { return $this->events; }  public function addEvent( SG_iCal_VEvent $event ) { $this->events[] = $event; } }  class SG_iCalReader extends SG_iCal {}   class SG_iCal_VCalendar implements IteratorAggregate { private $data;  public function __construct($data) { $this->data = $data; }  public function getTitle() { if( isset($this->data[\'x-wr-calname\']) ) { return $this->data[\'x-wr-calname\']; } else { return null; } }  public function getDescription() { if( isset($this->data[\'x-wr-caldesc\']) ) { return $this->data[\'x-wr-caldesc\']; } else { return null; } }  public function getIterator() { return new ArrayIterator($this->data); } }   class SG_iCal_VEvent { const DEFAULT_CONFIRMED = true; private $uid; private $start; private $end; private $recurrence; private $summary; private $description; private $location; private $data;  public function __construct($data, SG_iCal $ical ) { $this->uid = $data[\'uid\']->getData(); unset($data[\'uid\']); if ( isset($data[\'rrule\']) ) { $this->recurrence = new SG_iCal_Recurrence($data[\'rrule\']); unset($data[\'rrule\']); } if( isset($data[\'dtstart\']) ) { $this->start = $this->getTimestamp( $data[\'dtstart\'], $ical ); unset($data[\'dtstart\']); } if( isset($data[\'dtend\']) ) { $this->end = $this->getTimestamp($data[\'dtend\'], $ical); unset($data[\'dtend\']); } elseif( isset($data[\'duration\']) ) {    $dur = new SG_iCal_Duration( $data[\'duration\']->getData() ); $this->end = $this->start + $dur->getDuration(); unset($data[\'duration\']); } elseif ( isset($this->recurrence) ) {  $until = $this->recurrence->getUntil(); $count = $this->recurrence->getCount();  if ( $this->recurrence->getUntil() or $this->recurrence->getCount() ) {  if ( $until ) { $this->end = strtotime( $until ); }  } } $imports = array(\'summary\',\'description\',\'location\'); foreach( $imports AS $import ) { if( isset($data[$import]) ) { $this->$import = $data[$import]->getData(); unset($data[$import]); } } $this->data = SG_iCal_Line::Remove_Line($data); }  public function getUID() { return $this->uid; }  public function getSummary() { return $this->summary; }  public function getDescription() { return $this->description; }  public function getLocation() { return $this->location; }  public function isBlocking() { return !(isset($this->data[\'transp\']) && $this->data[\'transp\'] == \'TRANSPARENT\'); }  public function isConfirmed() { if( !isset($this->data[\'status\']) ) { return self::DEFAULT_CONFIRMED; } else { return $this->data[\'status\'] == \'CONFIRMED\'; } }  public function getStart() { return $this->start; }  public function getEnd() { return $this->end; }  public function getDuration() { return $this->end - $this->start; }  public function getProperty( $prop ) { if( isset($this->$prop) ) { return $this->$prop; } elseif( isset($this->data[$prop]) ) { return $this->data[$prop]; } else { return null; } }  private function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) { $ts = strtotime($line->getData()); if( isset($line[\'tzid\']) ) { $tz = $ical->getTimeZoneInfo($line[\'tzid\']); $offset = $tz->getOffset($ts); $ts = strtotime(date(\'D, d M Y H:i:s\', $ts) . \' \' . $offset); } return $ts; } }   class SG_iCal_VTimeZone { private $tzid; private $daylight; private $standard; private $cache = array();  public function __construct( $data ) {    $this->tzid = $data[\'tzid\']; $this->daylight = $data[\'daylight\']; $this->standard = $data[\'standard\']; }  public function getTimeZoneId() { return $this->tzid; }  public function getOffset( $ts ) { $act = $this->getActive($ts); return $this->{$act}[\'tzoffsetto\']; }  public function getTimeZoneName($ts) { $act = $this->getActive($ts); return $this->{$act}[\'tzname\']; }  private function getActive( $ts ) { if( isset($this->cache[$ts]) ) { return $this->cache[$ts]; } $daylight_freq = new SG_iCal_Freq($this->daylight[\'rrule\'], strtotime($this->daylight[\'dtstart\'])); $standard_freq = new SG_iCal_Freq($this->standard[\'rrule\'], strtotime($this->standard[\'dtstart\'])); $last_standard = $standard_freq->previousOccurrence($ts); $last_dst = $daylight_freq->previousOccurrence($ts); if( $last_dst > $last_standard ) { $this->cache[$ts] = \'daylight\'; } else { $this->cache[$ts] = \'standard\'; } return $this->cache[$ts]; } }   class SG_iCal_Duration { private $dur;  public function __construct( $duration ) { if( $duration{0} == \'P\' || (($duration{0} == \'+\' || $duration{0} == \'-\') && $duration{1} == \'P\') ) { preg_match(\'/P((\\d+)W)?((\\d+)D)?(T)?((\\d+)H)?((\\d+)M)?((\\d+)S)?/\', $duration, $matches); $results = array(\'weeks\'=>(int)$matches[2], \'days\'=>(int)$matches[4], \'hours\'=>(int)$matches[7], \'minutes\'=>(int)$matches[9], \'seconds\'=>(int)$matches[11]); $ts = 0; $ts += $results[\'seconds\']; $ts += 60 * $results[\'minutes\']; $ts += 60 * 60 * $results[\'hours\']; $ts += 24 * 60 * 60 * $results[\'days\']; $ts += 7 * 24 * 60 * 60 * $results[\'weeks\']; $dir = ($duration{0} == \'-\') ? -1 : 1; $this->dur = $dir * $ts; } else {  $this->dur = 0; } }  public function getDuration() { return $this->dur; } }   class SG_iCal_Factory {  public static function factory( SG_iCal $ical, $section, $data ) { switch( $section ) { case \"vcalendar\":    return new SG_iCal_VCalendar(SG_iCal_Line::Remove_Line($data), $ical ); case \"vtimezone\":    return new SG_iCal_VTimeZone(SG_iCal_Line::Remove_Line($data), $ical ); case \"vevent\":    return new SG_iCal_VEvent($data, $ical ); default: return new ArrayObject(SG_iCal_Line::Remove_Line((array) $data) ); } } }   class SG_iCal_Freq { private $weekdays = array(\'MO\'=>\'monday\', \'TU\'=>\'tuesday\', \'WE\'=>\'wednesday\', \'TH\'=>\'thursday\', \'FR\'=>\'friday\', \'SA\'=>\'saturday\', \'SU\'=>\'sunday\'); private $knownRules = array(\'month\', \'weekno\', \'day\', \'monthday\', \'yearday\', \'hour\', \'minute\'); private $simpleMode = true; private $rules = array(\'freq\'=>\'yearly\', \'interval\'=>1); private $start = 0; private $freq = \'\';  public function __construct( $rule, $start ) { $this->start = $start; $rules = array(); foreach( explode(\';\', $rule) AS $v) { list($k, $v) = explode(\'=\', $v); $this->rules[ strtolower($k) ] = $v; } if( isset($this->rules[\'until\']) && is_string($this->rules[\'until\']) ) { $this->rules[\'until\'] = strtotime($this->rules[\'until\']); } $this->freq = strtolower($this->rules[\'freq\']); foreach( $this->knownRules AS $rule ) { if( isset($this->rules[\'by\' . $rule]) ) { if( $this->isPrerule($rule, $this->freq) ) { $this->simpleMode = false; } } } if(!$this->simpleMode) { if(! (isset($this->rules[\'byday\']) || isset($this->rules[\'bymonthday\']) || isset($this->rules[\'byyearday\']))) { $this->rules[\'bymonthday\'] = date(\'d\', $this->start); } } if( isset($this->rules[\'count\']) ) { $n = $start; for($i=0;$i<$this->rules[\'count\'];$i++) { $n = $this->findNext($n); } $this->rules[\'until\'] = $n; } }  public function previousOccurrence( $offset ) { $t1 = $this->start; while( ($t2 = $this->findNext($t1)) < $offset) { if( $t2 == false ){ break; } $t1 = $t2; } return $t1; }  public function nextOccurrence( $offset ) { return $this->findNext( $this->previousOccurrence( $offset) ); }  public function lastOccurrence() { $temp_timestamp = $this->findNext($this->start); $timestamp = 0; while ($temp_timestamp) { $timestamp = $temp_timestamp; $temp_timestamp = $this->findNext($temp_timestamp); } return $timestamp; }  public function findNext($offset) { $echo = false;  if( $offset === false || (isset($this->rules[\'until\']) && $this->rules[\'until\'] <= $offset) ) { if($echo) echo \'STOP: \' . date(\'r\', $offset) . \"\\n\"; return false; } $found = true;   if($echo) echo \'O: \' . date(\'r\', $offset) . \"\\n\"; $hour = (in_array($this->freq, array(\'hourly\',\'minutely\')) && $offset > $this->start) ? date(\'H\', $offset) : date(\'H\', $this->start); $minute = (($this->freq == \'minutely\' || isset($this->rules[\'byminute\'])) && $offset > $this->start) ? date(\'i\', $offset) : date(\'i\', $this->start); $t = mktime($hour, $minute, date(\'s\', $this->start), date(\'m\', $offset), date(\'d\', $offset), date(\'Y\',$offset)); if($echo) echo \'START: \' . date(\'r\', $t) . \"\\n\"; if( $this->simpleMode ) { if( $offset < $t ) { return $t; } $next = $this->findStartingPoint( $t, $this->rules[\'interval\'], false ); if( !$this->validDate( $next ) ) { return $this->findNext($next); } return $next; } $eop = $this->findEndOfPeriod($offset); if($echo) echo \'EOP: \' . date(\'r\', $eop) . \"\\n\"; foreach( $this->knownRules AS $rule ) { if( $found && isset($this->rules[\'by\' . $rule]) ) { if( $this->isPrerule($rule, $this->freq) ) { $subrules = explode(\',\', $this->rules[\'by\' . $rule]); $_t = null; foreach( $subrules AS $subrule ) { $imm = call_user_func_array(array($this, \'ruleBy\' . $rule), array($subrule, $t)); if( $imm === false ) { break; } if($echo) echo strtoupper($rule) . \': \' . date(\'r\', $imm) . \' A: \' . ((int) ($imm > $offset && $imm < $eop)) . \"\\n\"; if( $imm > $offset && $imm < $eop && ($_t == null || $imm < $_t) ) { $_t = $imm; } } if( $_t !== null ) { $t = $_t; } else { $found = $this->validDate($t); } } } } if( $this->start > $offset && $this->start < $t ) { return $this->start; } else if( $found && ($t != $offset)) { if( $this->validDate( $t ) ) { if($echo) echo \'OK\' . \"\\n\"; return $t; } else { if($echo) echo \'Invalid\' . \"\\n\"; return $this->findNext($t); } } else { if($echo) echo \'Not found\' . \"\\n\"; return $this->findNext( $this->findStartingPoint( $offset, $this->rules[\'interval\'] ) ); } }  private function findStartingPoint( $offset, $interval, $truncate = true ) { $_freq = ($this->freq == \'daily\') ? \'day__\' : $this->freq; $t = \'+\' . $interval . \' \' . substr($_freq,0,-2) . \'s\'; if( $_freq == \'monthly\' && $truncate ) { if( $interval > 1) { $offset = strtotime(\'+\' . ($interval - 1) . \' months \', $offset); } $t = \'+\' . (date(\'t\', $offset) - date(\'d\', $offset) + 1) . \' days\'; } $sp = strtotime($t, $offset); if( $truncate ) { $sp = $this->truncateToPeriod($sp, $this->freq); } return $sp; }  public function findEndOfPeriod($offset) { return $this->findStartingPoint($offset, 1); }  private function truncateToPeriod( $time, $freq ) { $date = getdate($time); switch( $freq ) { case \"yearly\": $date[\'mon\'] = 1; case \"monthly\": $date[\'mday\'] = 1; case \"daily\": $date[\'hours\'] = 0; case \'hourly\': $date[\'minutes\'] = 0; case \"minutely\": $date[\'seconds\'] = 0; break; case \"weekly\": if( date(\'N\', $time) == 1) { $date[\'hours\'] = 0; $date[\'minutes\'] = 0; $date[\'seconds\'] = 0; } else { $date = getdate(strtotime(\"last monday 0:00\", $time)); } break; } $d = mktime($date[\'hours\'], $date[\'minutes\'], $date[\'seconds\'], $date[\'mon\'], $date[\'mday\'], $date[\'year\']); return $d; }  private function ruleByday($rule, $t) { $dir = ($rule{0} == \'-\') ? -1 : 1; $dir_t = ($dir == 1) ? \'next\' : \'last\'; $d = $this->weekdays[substr($rule,-2)]; $s = $dir_t . \' \' . $d . \' \' . date(\'H:i:s\',$t); if( $rule == substr($rule, -2) ) { if( date(\'l\', $t) == ucfirst($d) ) { $s = \'today \' . date(\'H:i:s\',$t); } $_t = strtotime($s, $t); if( $_t == $t && in_array($this->freq, array(\'monthly\', \'yearly\')) ) {  $s = \'next \' . $d . \' \' . date(\'H:i:s\',$t); $_t = strtotime($s, $_t); } return $_t; } else { $_f = $this->freq; if( isset($this->rules[\'bymonth\']) && $this->freq == \'yearly\' ) { $this->freq = \'monthly\'; } if( $dir == -1 ) { $_t = $this->findEndOfPeriod($t); } else { $_t = $this->truncateToPeriod($t, $this->freq); } $this->freq = $_f; $c = preg_replace(\'/[^0-9]/\',\'\',$rule); $c = ($c == \'\') ? 1 : $c; $n = $_t; while($c > 0 ) { if( $dir == 1 && $c == 1 && date(\'l\', $t) == ucfirst($d) ) { $s = \'today \' . date(\'H:i:s\',$t); } $n = strtotime($s, $n); $c--; } return $n; } } private function ruleBymonth($rule, $t) { $_t = mktime(date(\'H\',$t), date(\'i\',$t), date(\'s\',$t), $rule, date(\'d\', $t), date(\'Y\', $t)); if( $t == $_t && isset($this->rules[\'byday\']) ) {  return false; } else { return $_t; } } private function ruleBymonthday($rule, $t) { if( $rule < 0 ) { $rule = date(\'t\', $t) + $rule + 1; } return mktime(date(\'H\',$t), date(\'i\',$t), date(\'s\',$t), date(\'m\', $t), $rule, date(\'Y\', $t)); } private function ruleByyearday($rule, $t) { if( $rule < 0 ) { $_t = $this->findEndOfPeriod(); $d = \'-\'; } else { $_t = $this->truncateToPeriod($t, $this->freq); $d = \'+\'; } $s = $d . abs($rule -1) . \' days \' . date(\'H:i:s\',$t); return strtotime($s, $_t); } private function ruleByweekno($rule, $t) { if( $rule < 0 ) { $_t = $this->findEndOfPeriod(); $d = \'-\'; } else { $_t = $this->truncateToPeriod($t, $this->freq); $d = \'+\'; } $sub = (date(\'W\', $_t) == 1) ? 2 : 1; $s = $d . abs($rule - $sub) . \' weeks \' . date(\'H:i:s\',$t); $_t = strtotime($s, $_t); return $_t; } private function ruleByhour($rule, $t) { $_t = mktime($rule, date(\'i\',$t), date(\'s\',$t), date(\'m\',$t), date(\'d\', $t), date(\'Y\', $t)); return $_t; } private function ruleByminute($rule, $t) { $_t = mktime(date(\'h\',$t), $rule, date(\'s\',$t), date(\'m\',$t), date(\'d\', $t), date(\'Y\', $t)); return $_t; } private function validDate( $t ) { if( isset($this->rules[\'until\']) && $this->rules[\'until\'] <= $t ) { return false; } if( isset($this->rules[\'bymonth\']) ) { $months = explode(\',\', $this->rules[\'bymonth\']); if( !in_array(date(\'m\', $t), $months)) { return false; } } if( isset($this->rules[\'byday\']) ) { $days = explode(\',\', $this->rules[\'byday\']); foreach( $days As $i => $k ) { $days[$i] = $this->weekdays[ preg_replace(\'/[^A-Z]/\', \'\', $k)]; } if( !in_array(strtolower(date(\'l\', $t)), $days)) { return false; } } if( isset($this->rules[\'byweekno\']) ) { $weeks = explode(\',\', $this->rules[\'byweekno\']); if( !in_array(date(\'W\', $t), $weeks)) { return false; } } if( isset($this->rules[\'bymonthday\'])) { $weekdays = explode(\',\', $this->rules[\'bymonthday\']); foreach( $weekdays As $i => $k ) { if( $k < 0 ) { $weekdays[$i] = date(\'t\', $t) + $k + 1; } } if( !in_array(date(\'d\', $t), $weekdays)) { return false; } } if( isset($this->rules[\'byhour\']) ) { $hours = explode(\',\', $this->rules[\'byhour\']); if( !in_array(date(\'H\', $t), $hours)) { return false; } } return true; } private function isPrerule($rule, $freq) { if( $rule == \'year\') return false; if( $rule == \'month\' && $freq == \'yearly\') return true; if( $rule == \'monthday\' && in_array($freq, array(\'yearly\', \'monthly\')) && !isset($this->rules[\'byday\'])) return true;  if( $rule == \'yearday\' && $freq == \'yearly\' ) return true; if( $rule == \'weekno\' && $freq == \'yearly\' ) return true; if( $rule == \'day\' && in_array($freq, array(\'yearly\', \'monthly\', \'weekly\'))) return true; if( $rule == \'hour\' && in_array($freq, array(\'yearly\', \'monthly\', \'weekly\', \'daily\'))) return true; if( $rule == \'minute\' ) return true; return false; } }   class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate { private $ident; private $data; private $params = array(); private $replacements = array(\'from\'=>array(\'\\\\,\', \'\\\\n\', \'\\\\;\', \'\\\\:\', \'\\\\\"\'), \'to\'=>array(\',\', \"\\n\", \';\', \':\', \'\"\'));  public function __construct( $line ) { $split = strpos($line, \':\'); $idents = explode(\';\', substr($line, 0, $split)); $ident = strtolower(array_shift($idents)); $data = trim(substr($line, $split+1)); $data = str_replace($this->replacements[\'from\'], $this->replacements[\'to\'], $data); $params = array(); foreach( $idents AS $v) { list($k, $v) = explode(\'=\', $v); $params[ strtolower($k) ] = $v; } $this->ident = $ident; $this->params = $params; $this->data = $data; }  public function isBegin() { return $this->ident == \'begin\'; }  public function isEnd() { return $this->ident == \'end\'; }  public function getIdent() { return $this->ident; }  public function getData() { return $this->data; }  public static function Remove_Line($arr) { $rtn = array(); foreach( $arr AS $k => $v ) { if(is_array($v)) { $rtn[$k] = self::Remove_Line($v); } elseif( $v instanceof SG_iCal_Line ) { $rtn[$k] = $v->getData(); } else { $rtn[$k] = $v; } } return $rtn; }  public function offsetExists( $param ) { return isset($this->params[ strtolower($param) ]); }  public function offsetGet( $param ) { $index = strtolower($param); if (isset($this->params[ $index ])) { return $this->params[ $index ]; } }  public function offsetSet( $param, $val ) { return false; }  public function offsetUnset( $param ) { return false; }  public function __toString() { return $this->getData(); }  public function count() { return count($this->params); }  public function getIterator() { return new ArrayIterator($this->params); } }  class SG_iCal_Parser {  public static function Parse( $url, SG_iCal $ical ) { $content = self::Fetch( $url ); $content = self::UnfoldLines($content); self::_Parse( $content, $ical ); }  public static function ParseString($content, SG_iCal $ical ) { $content = self::UnfoldLines($content); self::_Parse( $content, $ical ); }  protected static function Fetch( $url ) { $c = curl_init(); $is_utf8 = true; curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); if( !ini_get(\'safe_mode\') ){ curl_setopt($c, CURLOPT_FOLLOWLOCATION, true); } $content = curl_exec($c); $ct = curl_getinfo($c, CURLINFO_CONTENT_TYPE); $enc = preg_replace(\'/^.*charset=([-a-zA-Z0-9]+).*$/\', \'$1\', $ct); if( $ct != \'\' && strtolower(str_replace(\'-\',\'\', $enc)) != \'utf8\' ) {  $is_utf8 = false; } elseif( ! self::_ValidUtf8( $content ) ) {  $is_utf8 = false; } if( !$is_utf8 ) { $content = utf8_encode($content); } return $content; }  protected static function UnfoldLines($content) { $data = array(); $content = explode(\"\\n\", $content); for( $i=0; $i < count($content); $i++) { $line = rtrim($content[$i]); while( isset($content[$i+1]) && strlen($content[$i+1]) > 0 && ($content[$i+1]{0} == \' \' || $content[$i+1]{0} == \"\\t\" )) { $line .= rtrim(substr($content[++$i],1)); } $data[] = $line; } return $data; }  private static function _Parse( $content, SG_iCal $ical ) { $main_sections = array(\'vevent\', \'vjournal\', \'vtodo\', \'vtimezone\', \'vcalendar\'); $sections = array(); $section = \'\'; $current_data = array(); foreach( $content AS $line ) { $line = new SG_iCal_Line($line); if( $line->isBegin() ) {  $section = strtolower($line->getData()); $sections[] = strtolower($line->getData()); } elseif( $line->isEnd() ) {  $removed = array_pop($sections); $section = end($sections); if( array_search($removed, $main_sections) !== false ) { self::StoreSection( $removed, $current_data[$removed], $ical); $current_data[$removed] = array(); } } else {  foreach( $main_sections AS $s ) {  if( array_search($s, $sections) !== false ) {  if( $section == $s ) {  $current_data[$s][$line->getIdent()] = $line; } else {  $current_data[$s][$section][$line->getIdent()] = $line; } break; } } } } $current_data = array(); }  protected static function storeSection( $section, $data, SG_iCal $ical ) { $data = SG_iCal_Factory::Factory($ical, $section, $data); switch( $section ) { case \'vcalendar\': return $ical->setCalendarInfo( $data ); case \'vevent\': return $ical->addEvent( $data ); case \'vjournal\': case \'vtodo\': return true;  case \'vtimezone\': return $ical->addTimeZone( $data ); } }  private static function _ValidUtf8( $data ) { $rx = \'[\\xC0-\\xDF]([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xE0-\\xEF].{0,1}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xF0-\\xF7].{0,2}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xF8-\\xFB].{0,3}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xFC-\\xFD].{0,4}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xFE-\\xFE].{0,5}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\x00-\\x7F][\\x80-\\xBF]\'; $rx .= \'|[\\xC0-\\xDF].[\\x80-\\xBF]\'; $rx .= \'|[\\xE0-\\xEF]..[\\x80-\\xBF]\'; $rx .= \'|[\\xF0-\\xF7]...[\\x80-\\xBF]\'; $rx .= \'|[\\xF8-\\xFB]....[\\x80-\\xBF]\'; $rx .= \'|[\\xFC-\\xFD].....[\\x80-\\xBF]\'; $rx .= \'|[\\xFE-\\xFE]......[\\x80-\\xBF]\'; $rx .= \'|^[\\x80-\\xBF]\'; return ( ! (bool) preg_match(\'!\'.$rx.\'!\', $data) ); } }   class SG_iCal_Query {  public static function Between( $ical, $start, $end ) { if( $ical instanceof SG_iCalReader ) { $ical = $ical->getEvents(); } if( !is_array($evs) ) { throw new Exception(\'SG_iCal_Query::Between called with invalid input!\'); } $rtn = array(); foreach( $evs AS $e ) { if( ($start <= $e->getStart() && $e->getStart() < $end) || ($start < $e->getEnd() && $e->getEnd() <= $end) ) { $rtn[] = $e; } } return $rtn; }  public static function After( $ical, $start ) { if( $ical instanceof SG_iCalReader ) { $ical = $ical->getEvents(); } if( !is_array($ical) ) { throw new Exception(\'SG_iCal_Query::After called with invalid input!\'); } $rtn = array(); foreach( $ical AS $e ) { if( $start <= $e->getStart() ) { $rtn[] = $e; } } return $rtn; }  public static function Sort( $ical, $column ) { if( $ical instanceof SG_iCalReader ) { $ical = $ical->getEvents(); } if( !is_array($ical) ) { throw new Exception(\'SG_iCal_Query::Sort called with invalid input!\'); } $cmp = create_function(\'$a, $b\', \'return strcmp($a->getProperty(\"\' . $column . \'\"), $b->getProperty(\"\' . $column . \'\"));\'); usort($ical, $cmp); return $ical; } } ','function mka_ical($atts, $thing = \'\') {\r\n	$time_start = microtime(true);\r\n	global $txpcfg;\r\n	extract(lAtts(array(\r\n		\'url\' => \'\',\r\n		\'cachingtime\' => 30,\r\n		\'googlemail\' => \'\',\r\n		\'limit\' => 0,\r\n		\'pastevents\' => false,\r\n		\'fmtTime\' => \'H:i\',\r\n		\'fmtDate\' => \'d.m.Y\',\r\n		\'imgfolder\' => \'\',\r\n		\'imgcat\' => \'\',	\r\n		\'defaultimage\' => \'none.gif\',\r\n		\'break\'  => \'li\',\r\n		\'class\' => __FUNCTION__,\r\n		\'cssid\' => \'icalevents\',\r\n		\'wraptag\'  => \'ul\',\r\n		\'form\'  => \'\'\r\n	), $atts));\r\n	\r\n	if (strlen($thing) > 0) {\r\n		$body = $thing;\r\n	} else if (!empty($form)) {\r\n		$body = fetch_form($form);\r\n	} else {\r\n		// Default body\r\n		$body = \'<li><span class=\"date\">{date}</span>\'\r\n				.\'<span class=\"title\">{summary}</span>\'\r\n				.\'<span class=\"description\">{description}</span></li>\';\r\n	}\r\n\r\n	// get url from googlemail-address\r\n	if (strlen($googlemail) > 0) {\r\n		$tmp = explode(\"@\", $googlemail);\r\n		$gmail = $tmp[0];\r\n		$urls[] = \"http://www.google.com/calendar/ical/\".$googlemail.\"%40googlemail.com/public/basic.ics\";\r\n	}\r\n	\r\n	// add given urls from attribute url\r\n	if (strlen($url) > 0) {\r\n		foreach (explode(\",\", $url) as $u)\r\n			$urls[] = trim($u);\r\n	}\r\n	\r\n	// no url --> Nothing to show.\r\n	if (sizeof($urls) === 0) {\r\n		return \"Error: No url given.\";\r\n	}\r\n	\r\n	// get images from folder and/or category\r\n	$show_img = false;\r\n	if ((strlen($imgcat) > 0) || (strlen($imgfolder) > 0 )) {\r\n		$images = array();\r\n		\r\n		// add images from given categories\r\n		if (strlen($imgcat) > 0) {\r\n			$images = mka_imgarrayfromcat($imgcat);	\r\n		}\r\n		\r\n		// Add images from given folder\r\n		if (file_exists($imgfolder)) {\r\n			$images = array_merge(mka_imgarrayfromfolder($imgfolder));\r\n		}\r\n\r\n		if (sizeof($images) > 0) {\r\n			$show_img = true;\r\n\r\n			// get default image\r\n			$defimg = ical_defimg($defaultimage);\r\n		}\r\n	}\r\n\r\n	\r\n	// get events from cache\r\n	$events = checkCache($urls, $cachingtime);\r\n\r\n	\r\n	// loop trough events\r\n	$i = 1;\r\n	foreach ($events as $evt) {\r\n\r\n		// is event in future or running?\r\n		if (($pastevents || $evt->end > mktime()) && ($limit == 0 || $i <= $limit )) {\r\n\r\n			// TODO :: TextileRestricted($text, $lite = 1, $noimage = 1, $rel = \'nofollow\')\r\n			$evt->sum = ical_formatText($evt->sum);\r\n			$evt->des = ical_formatText($evt->des);\r\n\r\n			$dateView = ical_getDateView($evt, $fmtDate, $fmtTime);\r\n\r\n			if ($show_img) {\r\n				$image = ical_img($evt->sum, $images, $defimg);\r\n			}\r\n\r\n			// $output[] = parse();	\r\n			$keys = array(); $vals = array();\r\n			$keys[] = \'{date}\';		$vals[] = $dateView;\r\n			$keys[] = \'{title}\';		$vals[] = $evt->sum;\r\n			$keys[] = \'{description}\';	$vals[] = $evt->des;\r\n			$keys[] = \'{imagesrc}\';		$vals[] = $image[\'src\'];\r\n			$keys[] = \'{imageid}\';		$vals[] = $image[\'id\'];\r\n\r\n			\r\n			$out[] = parse(str_replace($keys, $vals, $body));\r\n			\r\n			$i++; // count for attr limit\r\n		} // if ($evt->getEnd() > mktime() && ($limit == 0  || $i <= $limit ))\r\n\r\n	}\r\n	\r\n	$gen =  \"<!-- mka_ical - generated in \".((microtime(true)-$time_start)*1000).\"ms -->\";\r\n	// definition of doWrap\r\n	// http://www.consking.com/txp406/nav.html?textpattern/publish/taghandlers.php.html#dowrap\r\n	return doWrap($out, $wraptag, $break, $class, \'\', \'\', \'\', $cssid).$gen;\r\n	\r\n}\r\n\r\n\r\nfunction ical_img($title, $images, $defimg) {\r\n	$search = array(\" \", \".\", \"-\");\r\n	$rep = array(\"\", \"\", \"\");\r\n	$t = str_replace($search, $rep, strtolower($title));\r\n	foreach ($images as $im) {\r\n		if (strpos($t, $im[\'name\']) !== false) {\r\n			return $im;\r\n		}\r\n	}\r\n	// return default image src\r\n	return $defimg;\r\n}\r\n\r\n\r\nfunction ical_getDateView($evt, $fmtDate, $fmtTime) {\r\n	$fmtDaTi = $fmtDate.\" \".$fmtTime;\r\n	// event on one day\r\n	if (date(\"dmY\",$evt->start) == date(\"dmY\",$evt->end-1)) {\r\n		// no exact time definition\r\n		if (date(\"H:i\",$evt->start) == \"00:00\" && date(\"H:i\",$evt->end) == \"00:00\") {\r\n			$dateView = date($fmtDate, $evt->start);\r\n		}\r\n		else {\r\n			$dateView = date($fmtDaTi, $evt->start).\"-\".date($fmtTime, $evt->start + $evt->duration);\r\n		}\r\n	\r\n	}	\r\n	else {\r\n		$dateView  = date($fmtDate, $evt->start).\"-\".date($fmtDate, $evt->end-1);\r\n	}\r\n	return $dateView;\r\n}\r\n\r\nfunction mka_makearr_sql($str, $type=\'string\', $delimeter =\',\') {\r\n	$ret = array();\r\n	$arr = explode($delimeter, $str);\r\n	foreach ($arr as $el) {\r\n		if ($type == \'string\')\r\n			$ret[] = \"\'\".trim($el).\"\'\";\r\n		else \r\n			$ret[] = $el;\r\n	}\r\n	return $ret;\r\n}\r\n\r\nfunction mka_imgarrayfromcat($cats) {\r\n	$imgs = array();\r\n	\r\n	$cats = mka_makearr_sql($cats);\r\n	$clause = \'category IN (\'.implode(\",\", $cats).\')\';\r\n	$attrs = \'id, name, ext\';\r\n	$rs = safe_rows($attrs,\'txp_image\', $clause);\r\n	\r\n	$prefix = \"http://\".$GLOBALS[\'prefs\'][\"siteurl\"].\"/\".$GLOBALS[\'prefs\'][\'img_dir\'].\"/\";\r\n	\r\n	if (count($rs) != 0) {\r\n		foreach ($rs as $col) {\r\n			$col[\'src\'] = $prefix.$col[\'id\'].$col[\'ext\'];\r\n			$imgs[] = $col;	\r\n		}\r\n	}\r\n	return $imgs;\r\n}\r\n\r\nfunction mka_imgarrayfromfolder($imgfolder) {\r\n	$imgs = array();\r\n	if ($handle = @opendir($imgfolder)) {\r\n		while (($file = @readdir($handle)) !== false) {\r\n			$img = array();\r\n			$parts = explode(\".\", $file);\r\n			$img[\'ext\']  = (count($parts) > 1) ? \".\".array_pop($parts) : \'\';\r\n			$img[\'name\'] = implode(\".\", $parts);\r\n			$img[\'src\'] = \"http://\".$GLOBALS[\'prefs\'][\"siteurl\"].\"/\".$imgfolder.\"/\".$file;\r\n			if (strlen($img[\'name\']) > 0 && in_array(strtolower($img[\'ext\']), array(\".png\", \".jpg\", \".jpeg\", \".gif\"))) {\r\n				$imgs[] = $img;\r\n			}\r\n		}\r\n		closedir($handle);\r\n	}\r\n	return $imgs;\r\n}\r\n\r\n\r\nfunction ical_defimg($defimg) {\r\n	$url = \"http://\".$GLOBALS[\'prefs\'][\"siteurl\"].\"/\";\r\n	$img = array();\r\n	// is defimg id?\r\n	if (intval($defimg) !== 0) {\r\n		$id = intval($defimg);\r\n		$img = safe_row(\'id, name, ext\', \'txp_image\', \'id = \'.$id);\r\n	}\r\n	\r\n	// image with id not found?\r\n	if (sizeof($img) === 0) {\r\n		$parts = explode(\".\", basename($defimg));\r\n		$img[\'ext\']  = (count($parts) > 1) ? \".\".array_pop($parts) : \'\';\r\n		$img[\'name\'] = implode(\".\", $parts);\r\n		$img[\'src\'] = $url.$defimg;\r\n	}\r\n	else {\r\n		$img[\"src\"] = $url.$GLOBALS[\'prefs\'][\'img_dir\'].\"/\".$img[\'id\'].$img[\'ext\'];\r\n	}\r\n	return $img;\r\n}\r\n\r\nfunction ical_shorten_link($string) {\r\n	$text_word_maxlength = 55;\r\n	if(count($string) == 2) { $pre = \"\"; $url = $string[1]; }\r\n	else { $pre = $string[1]; $url = $string[2]; }\r\n	$shortened_url = $url;\r\n	if (strlen($url) > $text_word_maxlength) $shortened_url = substr($url, 0, ($text_word_maxlength/2)) . \"...\" . substr($url, - ($text_word_maxlength-3-$text_word_maxlength/2));\r\n	return $pre.\"<a href=\\\"\".$url.\"\\\">\".$shortened_url.\"</a>\";\r\n}\r\n\r\nfunction ical_formatText($string) {\r\n	$string = \' \' . $string;\r\n	$string = preg_replace_callback(\"#(^|[\\n ])([\\w]+?://.*?[^ \\\"\\n\\r\\t<]*)#is\", \"ical_shorten_link\", $string);\r\n	$string = preg_replace(\"#(^|[\\n ])((www|ftp)\\.[\\w\\-]+\\.[\\w\\-.\\~]+(?:/[^ \\\"\\t\\n\\r<]*)?)#is\", \"$1<a href=\\\"http://$2\\\">$2</a>\", $string);\r\n	$string = str_replace(\"\\n\",\"<br/>\",$string);\r\n	return $string;\r\n}\r\n function checkCache($urls, $cachingtime) { $hash = md5(implode(\",\", $urls)); $fn = \"files/mka_ical_\".$hash.\".json\"; if (file_exists($fn) && (time()-filemtime($fn) < ($cachingtime*60))) {  $cache_file = fopen($fn,\"r\"); $data = fread($cache_file, filesize($fn)); fclose($cache_file); return json_decode($data); } else {  $events = getEvents($urls); $cf = fopen($fn,\"w+\"); fwrite($cf, json_encode($events)); fclose($cf); return $events; } } function getEvents($urls) { $events = array(); $reader = new SG_iCal(); foreach($urls as $u) { $reader->setUrl($u, true); $e = $reader->getEvents(); foreach($e as $event) { $events[] = getPlainEvent($event); } }  usort($events, \"cmp_event\"); return $events; } function getPlainEvent($evt) { $plainEvent = new stdClass; $plainEvent->start = $evt->getStart(); $plainEvent->end = $evt->getEnd(); $plainEvent->duration = $evt->getDuration(); $plainEvent->sum = $evt->getSummary(); $plainEvent->des = $evt->getDescription(); $plainEvent->loc = $evt->getLocation(); return $plainEvent; } function cmp_event($a, $b) { $da = $a->start; $db = $b->start; if ($da == $db) { return 1; } return ($da < $db) ? -1 : 1; }  define(\'SG_ICALREADER_VERSION\', \'0.5\');  class SG_iCal { private $information; private $events; private $timezones;  public function __construct($url = false) {                     if( $url !== false ) { SG_iCal_Parser::Parse($url, $this); } }  public function setUrl( $url = false ) { if( $url !== false ) { SG_iCal_Parser::Parse($url, $this); } }  public function getCalendarInfo() { return $this->information; }  public function setCalendarInfo( SG_iCal_VCalendar $info ) { $this->information = $info; }  public function getTimeZoneInfo( $tzid = null ) { if( $tzid == null ) { return $this->timezones; } else { if ( !isset($this->timezones)) { return null; } foreach( $this->timezones AS $tz ) { if( $tz->getTimeZoneId() == $tzid ) { return $tz; } } return null; } }  public function addTimeZone( SG_iCal_VTimeZone $tz ) { $this->timezones[] = $tz; }  public function getEvents() { return $this->events; }  public function addEvent( SG_iCal_VEvent $event ) { $this->events[] = $event; } }  class SG_iCalReader extends SG_iCal {}   class SG_iCal_VCalendar implements IteratorAggregate { private $data;  public function __construct($data) { $this->data = $data; }  public function getTitle() { if( isset($this->data[\'x-wr-calname\']) ) { return $this->data[\'x-wr-calname\']; } else { return null; } }  public function getDescription() { if( isset($this->data[\'x-wr-caldesc\']) ) { return $this->data[\'x-wr-caldesc\']; } else { return null; } }  public function getIterator() { return new ArrayIterator($this->data); } }   class SG_iCal_VEvent { const DEFAULT_CONFIRMED = true; private $uid; private $start; private $end; private $recurrence; private $summary; private $description; private $location; private $data;  public function __construct($data, SG_iCal $ical ) { $this->uid = $data[\'uid\']->getData(); unset($data[\'uid\']); if ( isset($data[\'rrule\']) ) { $this->recurrence = new SG_iCal_Recurrence($data[\'rrule\']); unset($data[\'rrule\']); } if( isset($data[\'dtstart\']) ) { $this->start = $this->getTimestamp( $data[\'dtstart\'], $ical ); unset($data[\'dtstart\']); } if( isset($data[\'dtend\']) ) { $this->end = $this->getTimestamp($data[\'dtend\'], $ical); unset($data[\'dtend\']); } elseif( isset($data[\'duration\']) ) {    $dur = new SG_iCal_Duration( $data[\'duration\']->getData() ); $this->end = $this->start + $dur->getDuration(); unset($data[\'duration\']); } elseif ( isset($this->recurrence) ) {  $until = $this->recurrence->getUntil(); $count = $this->recurrence->getCount();  if ( $this->recurrence->getUntil() or $this->recurrence->getCount() ) {  if ( $until ) { $this->end = strtotime( $until ); }  } } $imports = array(\'summary\',\'description\',\'location\'); foreach( $imports AS $import ) { if( isset($data[$import]) ) { $this->$import = $data[$import]->getData(); unset($data[$import]); } } $this->data = SG_iCal_Line::Remove_Line($data); }  public function getUID() { return $this->uid; }  public function getSummary() { return $this->summary; }  public function getDescription() { return $this->description; }  public function getLocation() { return $this->location; }  public function isBlocking() { return !(isset($this->data[\'transp\']) && $this->data[\'transp\'] == \'TRANSPARENT\'); }  public function isConfirmed() { if( !isset($this->data[\'status\']) ) { return self::DEFAULT_CONFIRMED; } else { return $this->data[\'status\'] == \'CONFIRMED\'; } }  public function getStart() { return $this->start; }  public function getEnd() { return $this->end; }  public function getDuration() { return $this->end - $this->start; }  public function getProperty( $prop ) { if( isset($this->$prop) ) { return $this->$prop; } elseif( isset($this->data[$prop]) ) { return $this->data[$prop]; } else { return null; } }  private function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) { $ts = strtotime($line->getData()); if( isset($line[\'tzid\']) ) { $tz = $ical->getTimeZoneInfo($line[\'tzid\']); $offset = $tz->getOffset($ts); $ts = strtotime(date(\'D, d M Y H:i:s\', $ts) . \' \' . $offset); } return $ts; } }   class SG_iCal_VTimeZone { private $tzid; private $daylight; private $standard; private $cache = array();  public function __construct( $data ) {    $this->tzid = $data[\'tzid\']; $this->daylight = $data[\'daylight\']; $this->standard = $data[\'standard\']; }  public function getTimeZoneId() { return $this->tzid; }  public function getOffset( $ts ) { $act = $this->getActive($ts); return $this->{$act}[\'tzoffsetto\']; }  public function getTimeZoneName($ts) { $act = $this->getActive($ts); return $this->{$act}[\'tzname\']; }  private function getActive( $ts ) { if( isset($this->cache[$ts]) ) { return $this->cache[$ts]; } $daylight_freq = new SG_iCal_Freq($this->daylight[\'rrule\'], strtotime($this->daylight[\'dtstart\'])); $standard_freq = new SG_iCal_Freq($this->standard[\'rrule\'], strtotime($this->standard[\'dtstart\'])); $last_standard = $standard_freq->previousOccurrence($ts); $last_dst = $daylight_freq->previousOccurrence($ts); if( $last_dst > $last_standard ) { $this->cache[$ts] = \'daylight\'; } else { $this->cache[$ts] = \'standard\'; } return $this->cache[$ts]; } }   class SG_iCal_Duration { private $dur;  public function __construct( $duration ) { if( $duration{0} == \'P\' || (($duration{0} == \'+\' || $duration{0} == \'-\') && $duration{1} == \'P\') ) { preg_match(\'/P((\\d+)W)?((\\d+)D)?(T)?((\\d+)H)?((\\d+)M)?((\\d+)S)?/\', $duration, $matches); $results = array(\'weeks\'=>(int)$matches[2], \'days\'=>(int)$matches[4], \'hours\'=>(int)$matches[7], \'minutes\'=>(int)$matches[9], \'seconds\'=>(int)$matches[11]); $ts = 0; $ts += $results[\'seconds\']; $ts += 60 * $results[\'minutes\']; $ts += 60 * 60 * $results[\'hours\']; $ts += 24 * 60 * 60 * $results[\'days\']; $ts += 7 * 24 * 60 * 60 * $results[\'weeks\']; $dir = ($duration{0} == \'-\') ? -1 : 1; $this->dur = $dir * $ts; } else {  $this->dur = 0; } }  public function getDuration() { return $this->dur; } }   class SG_iCal_Factory {  public static function factory( SG_iCal $ical, $section, $data ) { switch( $section ) { case \"vcalendar\":    return new SG_iCal_VCalendar(SG_iCal_Line::Remove_Line($data), $ical ); case \"vtimezone\":    return new SG_iCal_VTimeZone(SG_iCal_Line::Remove_Line($data), $ical ); case \"vevent\":    return new SG_iCal_VEvent($data, $ical ); default: return new ArrayObject(SG_iCal_Line::Remove_Line((array) $data) ); } } }   class SG_iCal_Freq { private $weekdays = array(\'MO\'=>\'monday\', \'TU\'=>\'tuesday\', \'WE\'=>\'wednesday\', \'TH\'=>\'thursday\', \'FR\'=>\'friday\', \'SA\'=>\'saturday\', \'SU\'=>\'sunday\'); private $knownRules = array(\'month\', \'weekno\', \'day\', \'monthday\', \'yearday\', \'hour\', \'minute\'); private $simpleMode = true; private $rules = array(\'freq\'=>\'yearly\', \'interval\'=>1); private $start = 0; private $freq = \'\';  public function __construct( $rule, $start ) { $this->start = $start; $rules = array(); foreach( explode(\';\', $rule) AS $v) { list($k, $v) = explode(\'=\', $v); $this->rules[ strtolower($k) ] = $v; } if( isset($this->rules[\'until\']) && is_string($this->rules[\'until\']) ) { $this->rules[\'until\'] = strtotime($this->rules[\'until\']); } $this->freq = strtolower($this->rules[\'freq\']); foreach( $this->knownRules AS $rule ) { if( isset($this->rules[\'by\' . $rule]) ) { if( $this->isPrerule($rule, $this->freq) ) { $this->simpleMode = false; } } } if(!$this->simpleMode) { if(! (isset($this->rules[\'byday\']) || isset($this->rules[\'bymonthday\']) || isset($this->rules[\'byyearday\']))) { $this->rules[\'bymonthday\'] = date(\'d\', $this->start); } } if( isset($this->rules[\'count\']) ) { $n = $start; for($i=0;$i<$this->rules[\'count\'];$i++) { $n = $this->findNext($n); } $this->rules[\'until\'] = $n; } }  public function previousOccurrence( $offset ) { $t1 = $this->start; while( ($t2 = $this->findNext($t1)) < $offset) { if( $t2 == false ){ break; } $t1 = $t2; } return $t1; }  public function nextOccurrence( $offset ) { return $this->findNext( $this->previousOccurrence( $offset) ); }  public function lastOccurrence() { $temp_timestamp = $this->findNext($this->start); $timestamp = 0; while ($temp_timestamp) { $timestamp = $temp_timestamp; $temp_timestamp = $this->findNext($temp_timestamp); } return $timestamp; }  public function findNext($offset) { $echo = false;  if( $offset === false || (isset($this->rules[\'until\']) && $this->rules[\'until\'] <= $offset) ) { if($echo) echo \'STOP: \' . date(\'r\', $offset) . \"\\n\"; return false; } $found = true;   if($echo) echo \'O: \' . date(\'r\', $offset) . \"\\n\"; $hour = (in_array($this->freq, array(\'hourly\',\'minutely\')) && $offset > $this->start) ? date(\'H\', $offset) : date(\'H\', $this->start); $minute = (($this->freq == \'minutely\' || isset($this->rules[\'byminute\'])) && $offset > $this->start) ? date(\'i\', $offset) : date(\'i\', $this->start); $t = mktime($hour, $minute, date(\'s\', $this->start), date(\'m\', $offset), date(\'d\', $offset), date(\'Y\',$offset)); if($echo) echo \'START: \' . date(\'r\', $t) . \"\\n\"; if( $this->simpleMode ) { if( $offset < $t ) { return $t; } $next = $this->findStartingPoint( $t, $this->rules[\'interval\'], false ); if( !$this->validDate( $next ) ) { return $this->findNext($next); } return $next; } $eop = $this->findEndOfPeriod($offset); if($echo) echo \'EOP: \' . date(\'r\', $eop) . \"\\n\"; foreach( $this->knownRules AS $rule ) { if( $found && isset($this->rules[\'by\' . $rule]) ) { if( $this->isPrerule($rule, $this->freq) ) { $subrules = explode(\',\', $this->rules[\'by\' . $rule]); $_t = null; foreach( $subrules AS $subrule ) { $imm = call_user_func_array(array($this, \'ruleBy\' . $rule), array($subrule, $t)); if( $imm === false ) { break; } if($echo) echo strtoupper($rule) . \': \' . date(\'r\', $imm) . \' A: \' . ((int) ($imm > $offset && $imm < $eop)) . \"\\n\"; if( $imm > $offset && $imm < $eop && ($_t == null || $imm < $_t) ) { $_t = $imm; } } if( $_t !== null ) { $t = $_t; } else { $found = $this->validDate($t); } } } } if( $this->start > $offset && $this->start < $t ) { return $this->start; } else if( $found && ($t != $offset)) { if( $this->validDate( $t ) ) { if($echo) echo \'OK\' . \"\\n\"; return $t; } else { if($echo) echo \'Invalid\' . \"\\n\"; return $this->findNext($t); } } else { if($echo) echo \'Not found\' . \"\\n\"; return $this->findNext( $this->findStartingPoint( $offset, $this->rules[\'interval\'] ) ); } }  private function findStartingPoint( $offset, $interval, $truncate = true ) { $_freq = ($this->freq == \'daily\') ? \'day__\' : $this->freq; $t = \'+\' . $interval . \' \' . substr($_freq,0,-2) . \'s\'; if( $_freq == \'monthly\' && $truncate ) { if( $interval > 1) { $offset = strtotime(\'+\' . ($interval - 1) . \' months \', $offset); } $t = \'+\' . (date(\'t\', $offset) - date(\'d\', $offset) + 1) . \' days\'; } $sp = strtotime($t, $offset); if( $truncate ) { $sp = $this->truncateToPeriod($sp, $this->freq); } return $sp; }  public function findEndOfPeriod($offset) { return $this->findStartingPoint($offset, 1); }  private function truncateToPeriod( $time, $freq ) { $date = getdate($time); switch( $freq ) { case \"yearly\": $date[\'mon\'] = 1; case \"monthly\": $date[\'mday\'] = 1; case \"daily\": $date[\'hours\'] = 0; case \'hourly\': $date[\'minutes\'] = 0; case \"minutely\": $date[\'seconds\'] = 0; break; case \"weekly\": if( date(\'N\', $time) == 1) { $date[\'hours\'] = 0; $date[\'minutes\'] = 0; $date[\'seconds\'] = 0; } else { $date = getdate(strtotime(\"last monday 0:00\", $time)); } break; } $d = mktime($date[\'hours\'], $date[\'minutes\'], $date[\'seconds\'], $date[\'mon\'], $date[\'mday\'], $date[\'year\']); return $d; }  private function ruleByday($rule, $t) { $dir = ($rule{0} == \'-\') ? -1 : 1; $dir_t = ($dir == 1) ? \'next\' : \'last\'; $d = $this->weekdays[substr($rule,-2)]; $s = $dir_t . \' \' . $d . \' \' . date(\'H:i:s\',$t); if( $rule == substr($rule, -2) ) { if( date(\'l\', $t) == ucfirst($d) ) { $s = \'today \' . date(\'H:i:s\',$t); } $_t = strtotime($s, $t); if( $_t == $t && in_array($this->freq, array(\'monthly\', \'yearly\')) ) {  $s = \'next \' . $d . \' \' . date(\'H:i:s\',$t); $_t = strtotime($s, $_t); } return $_t; } else { $_f = $this->freq; if( isset($this->rules[\'bymonth\']) && $this->freq == \'yearly\' ) { $this->freq = \'monthly\'; } if( $dir == -1 ) { $_t = $this->findEndOfPeriod($t); } else { $_t = $this->truncateToPeriod($t, $this->freq); } $this->freq = $_f; $c = preg_replace(\'/[^0-9]/\',\'\',$rule); $c = ($c == \'\') ? 1 : $c; $n = $_t; while($c > 0 ) { if( $dir == 1 && $c == 1 && date(\'l\', $t) == ucfirst($d) ) { $s = \'today \' . date(\'H:i:s\',$t); } $n = strtotime($s, $n); $c--; } return $n; } } private function ruleBymonth($rule, $t) { $_t = mktime(date(\'H\',$t), date(\'i\',$t), date(\'s\',$t), $rule, date(\'d\', $t), date(\'Y\', $t)); if( $t == $_t && isset($this->rules[\'byday\']) ) {  return false; } else { return $_t; } } private function ruleBymonthday($rule, $t) { if( $rule < 0 ) { $rule = date(\'t\', $t) + $rule + 1; } return mktime(date(\'H\',$t), date(\'i\',$t), date(\'s\',$t), date(\'m\', $t), $rule, date(\'Y\', $t)); } private function ruleByyearday($rule, $t) { if( $rule < 0 ) { $_t = $this->findEndOfPeriod(); $d = \'-\'; } else { $_t = $this->truncateToPeriod($t, $this->freq); $d = \'+\'; } $s = $d . abs($rule -1) . \' days \' . date(\'H:i:s\',$t); return strtotime($s, $_t); } private function ruleByweekno($rule, $t) { if( $rule < 0 ) { $_t = $this->findEndOfPeriod(); $d = \'-\'; } else { $_t = $this->truncateToPeriod($t, $this->freq); $d = \'+\'; } $sub = (date(\'W\', $_t) == 1) ? 2 : 1; $s = $d . abs($rule - $sub) . \' weeks \' . date(\'H:i:s\',$t); $_t = strtotime($s, $_t); return $_t; } private function ruleByhour($rule, $t) { $_t = mktime($rule, date(\'i\',$t), date(\'s\',$t), date(\'m\',$t), date(\'d\', $t), date(\'Y\', $t)); return $_t; } private function ruleByminute($rule, $t) { $_t = mktime(date(\'h\',$t), $rule, date(\'s\',$t), date(\'m\',$t), date(\'d\', $t), date(\'Y\', $t)); return $_t; } private function validDate( $t ) { if( isset($this->rules[\'until\']) && $this->rules[\'until\'] <= $t ) { return false; } if( isset($this->rules[\'bymonth\']) ) { $months = explode(\',\', $this->rules[\'bymonth\']); if( !in_array(date(\'m\', $t), $months)) { return false; } } if( isset($this->rules[\'byday\']) ) { $days = explode(\',\', $this->rules[\'byday\']); foreach( $days As $i => $k ) { $days[$i] = $this->weekdays[ preg_replace(\'/[^A-Z]/\', \'\', $k)]; } if( !in_array(strtolower(date(\'l\', $t)), $days)) { return false; } } if( isset($this->rules[\'byweekno\']) ) { $weeks = explode(\',\', $this->rules[\'byweekno\']); if( !in_array(date(\'W\', $t), $weeks)) { return false; } } if( isset($this->rules[\'bymonthday\'])) { $weekdays = explode(\',\', $this->rules[\'bymonthday\']); foreach( $weekdays As $i => $k ) { if( $k < 0 ) { $weekdays[$i] = date(\'t\', $t) + $k + 1; } } if( !in_array(date(\'d\', $t), $weekdays)) { return false; } } if( isset($this->rules[\'byhour\']) ) { $hours = explode(\',\', $this->rules[\'byhour\']); if( !in_array(date(\'H\', $t), $hours)) { return false; } } return true; } private function isPrerule($rule, $freq) { if( $rule == \'year\') return false; if( $rule == \'month\' && $freq == \'yearly\') return true; if( $rule == \'monthday\' && in_array($freq, array(\'yearly\', \'monthly\')) && !isset($this->rules[\'byday\'])) return true;  if( $rule == \'yearday\' && $freq == \'yearly\' ) return true; if( $rule == \'weekno\' && $freq == \'yearly\' ) return true; if( $rule == \'day\' && in_array($freq, array(\'yearly\', \'monthly\', \'weekly\'))) return true; if( $rule == \'hour\' && in_array($freq, array(\'yearly\', \'monthly\', \'weekly\', \'daily\'))) return true; if( $rule == \'minute\' ) return true; return false; } }   class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate { private $ident; private $data; private $params = array(); private $replacements = array(\'from\'=>array(\'\\\\,\', \'\\\\n\', \'\\\\;\', \'\\\\:\', \'\\\\\"\'), \'to\'=>array(\',\', \"\\n\", \';\', \':\', \'\"\'));  public function __construct( $line ) { $split = strpos($line, \':\'); $idents = explode(\';\', substr($line, 0, $split)); $ident = strtolower(array_shift($idents)); $data = trim(substr($line, $split+1)); $data = str_replace($this->replacements[\'from\'], $this->replacements[\'to\'], $data); $params = array(); foreach( $idents AS $v) { list($k, $v) = explode(\'=\', $v); $params[ strtolower($k) ] = $v; } $this->ident = $ident; $this->params = $params; $this->data = $data; }  public function isBegin() { return $this->ident == \'begin\'; }  public function isEnd() { return $this->ident == \'end\'; }  public function getIdent() { return $this->ident; }  public function getData() { return $this->data; }  public static function Remove_Line($arr) { $rtn = array(); foreach( $arr AS $k => $v ) { if(is_array($v)) { $rtn[$k] = self::Remove_Line($v); } elseif( $v instanceof SG_iCal_Line ) { $rtn[$k] = $v->getData(); } else { $rtn[$k] = $v; } } return $rtn; }  public function offsetExists( $param ) { return isset($this->params[ strtolower($param) ]); }  public function offsetGet( $param ) { $index = strtolower($param); if (isset($this->params[ $index ])) { return $this->params[ $index ]; } }  public function offsetSet( $param, $val ) { return false; }  public function offsetUnset( $param ) { return false; }  public function __toString() { return $this->getData(); }  public function count() { return count($this->params); }  public function getIterator() { return new ArrayIterator($this->params); } }  class SG_iCal_Parser {  public static function Parse( $url, SG_iCal $ical ) { $content = self::Fetch( $url ); $content = self::UnfoldLines($content); self::_Parse( $content, $ical ); }  public static function ParseString($content, SG_iCal $ical ) { $content = self::UnfoldLines($content); self::_Parse( $content, $ical ); }  protected static function Fetch( $url ) { $c = curl_init(); $is_utf8 = true; curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); if( !ini_get(\'safe_mode\') ){ curl_setopt($c, CURLOPT_FOLLOWLOCATION, true); } $content = curl_exec($c); $ct = curl_getinfo($c, CURLINFO_CONTENT_TYPE); $enc = preg_replace(\'/^.*charset=([-a-zA-Z0-9]+).*$/\', \'$1\', $ct); if( $ct != \'\' && strtolower(str_replace(\'-\',\'\', $enc)) != \'utf8\' ) {  $is_utf8 = false; } elseif( ! self::_ValidUtf8( $content ) ) {  $is_utf8 = false; } if( !$is_utf8 ) { $content = utf8_encode($content); } return $content; }  protected static function UnfoldLines($content) { $data = array(); $content = explode(\"\\n\", $content); for( $i=0; $i < count($content); $i++) { $line = rtrim($content[$i]); while( isset($content[$i+1]) && strlen($content[$i+1]) > 0 && ($content[$i+1]{0} == \' \' || $content[$i+1]{0} == \"\\t\" )) { $line .= rtrim(substr($content[++$i],1)); } $data[] = $line; } return $data; }  private static function _Parse( $content, SG_iCal $ical ) { $main_sections = array(\'vevent\', \'vjournal\', \'vtodo\', \'vtimezone\', \'vcalendar\'); $sections = array(); $section = \'\'; $current_data = array(); foreach( $content AS $line ) { $line = new SG_iCal_Line($line); if( $line->isBegin() ) {  $section = strtolower($line->getData()); $sections[] = strtolower($line->getData()); } elseif( $line->isEnd() ) {  $removed = array_pop($sections); $section = end($sections); if( array_search($removed, $main_sections) !== false ) { self::StoreSection( $removed, $current_data[$removed], $ical); $current_data[$removed] = array(); } } else {  foreach( $main_sections AS $s ) {  if( array_search($s, $sections) !== false ) {  if( $section == $s ) {  $current_data[$s][$line->getIdent()] = $line; } else {  $current_data[$s][$section][$line->getIdent()] = $line; } break; } } } } $current_data = array(); }  protected static function storeSection( $section, $data, SG_iCal $ical ) { $data = SG_iCal_Factory::Factory($ical, $section, $data); switch( $section ) { case \'vcalendar\': return $ical->setCalendarInfo( $data ); case \'vevent\': return $ical->addEvent( $data ); case \'vjournal\': case \'vtodo\': return true;  case \'vtimezone\': return $ical->addTimeZone( $data ); } }  private static function _ValidUtf8( $data ) { $rx = \'[\\xC0-\\xDF]([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xE0-\\xEF].{0,1}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xF0-\\xF7].{0,2}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xF8-\\xFB].{0,3}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xFC-\\xFD].{0,4}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\xFE-\\xFE].{0,5}([^\\x80-\\xBF]|$)\'; $rx .= \'|[\\x00-\\x7F][\\x80-\\xBF]\'; $rx .= \'|[\\xC0-\\xDF].[\\x80-\\xBF]\'; $rx .= \'|[\\xE0-\\xEF]..[\\x80-\\xBF]\'; $rx .= \'|[\\xF0-\\xF7]...[\\x80-\\xBF]\'; $rx .= \'|[\\xF8-\\xFB]....[\\x80-\\xBF]\'; $rx .= \'|[\\xFC-\\xFD].....[\\x80-\\xBF]\'; $rx .= \'|[\\xFE-\\xFE]......[\\x80-\\xBF]\'; $rx .= \'|^[\\x80-\\xBF]\'; return ( ! (bool) preg_match(\'!\'.$rx.\'!\', $data) ); } }   class SG_iCal_Query {  public static function Between( $ical, $start, $end ) { if( $ical instanceof SG_iCalReader ) { $ical = $ical->getEvents(); } if( !is_array($evs) ) { throw new Exception(\'SG_iCal_Query::Between called with invalid input!\'); } $rtn = array(); foreach( $evs AS $e ) { if( ($start <= $e->getStart() && $e->getStart() < $end) || ($start < $e->getEnd() && $e->getEnd() <= $end) ) { $rtn[] = $e; } } return $rtn; }  public static function After( $ical, $start ) { if( $ical instanceof SG_iCalReader ) { $ical = $ical->getEvents(); } if( !is_array($ical) ) { throw new Exception(\'SG_iCal_Query::After called with invalid input!\'); } $rtn = array(); foreach( $ical AS $e ) { if( $start <= $e->getStart() ) { $rtn[] = $e; } } return $rtn; }  public static function Sort( $ical, $column ) { if( $ical instanceof SG_iCalReader ) { $ical = $ical->getEvents(); } if( !is_array($ical) ) { throw new Exception(\'SG_iCal_Query::Sort called with invalid input!\'); } $cmp = create_function(\'$a, $b\', \'return strcmp($a->getProperty(\"\' . $column . \'\"), $b->getProperty(\"\' . $column . \'\"));\'); usort($ical, $cmp); return $ical; } } ','cf6da719c8e0764baf77028b4ca7afb2',0,5,0),('glz_custom_fields',1,'Gerhard Lazu','http://gerhardlazu.com','1.2.4','Unlimited, super special custom fields.','<style type=\"text/css\" media=\"screen,projection\">\n  #glz_custom_fields_help {\n    margin: 0 auto;\n    font-family: Verdana,\"Lucida Grande\",sans-serif;\n    padding: 15px;\n    background-color: #F7F7F7;\n    border: 1px dotted #EBEBEB;\n    width: 700px;\n    color: #333;\n    font-size: 12px;\n    line-height:15px;\n  }\n  #glz_custom_fields_help p, #glz_custom_fields_help ul, #glz_custom_fields_help ol, #glz_custom_fields_help dl {\n    font-size: 12px;\n    line-height: 15px;\n    margin-bottom: 15px;\n  }\n  #glz_custom_fields_help ul {\n    padding-left: 15px;\n    list-style: square;\n  }\n  #glz_custom_fields_help ol {\n    padding-left: 20px;\n  }\n  #glz_custom_fields_help a, #glz_custom_fields_help a.visited {\n    color: #FF7B00;\n    text-decoration: none;\n    padding-bottom: 1px;\n    border-bottom: 1px dotted #FF7B00;\n  }\n  #glz_custom_fields_help a:hover {\n    color: #FFF;\n    background-color: #FF7B00;\n    border-bottom: 1px dotted #FF7B00;\n  }\n  #glz_custom_fields_help h1 {\n    font-family: Georgia,Times,Serif;\n    font-size: 24px;\n    font-weight: normal;\n    text-decoration: none;\n    line-height: 30px;\n    margin-bottom: 15px;\n    color: #333;\n    letter-spacing: -1px;\n  }\n  #glz_custom_fields_help h2 {\n    font-family: Georgia,Times,Serif;\n    color: #FFF;\n    font-size: 18px;\n    font-weight: normal;\n    line-height: 30px;\n    margin-bottom: 15px;\n    background-color: #C1C4C3;\n    padding-left: 15px;\n  }\n  #glz_custom_fields_help strong {\n\n  }\n  #glz_custom_fields_help code {\n    line-height: 16px;\n    font-style: italic;\n    font-family: Monaco,\"Courier New\", Courier, monospace;\n    font-size-adjust: none;\n    font-stretch: normal;\n    font-variant: normal;\n    font-weight: normal;\n    font-size: 12px;\n    color: #000;\n  }\n  #glz_custom_fields_help code.txp {\n    background-color: #FFF6A9;\n    font-family: Monaco,\"Courier New\", Courier, monospace;\n    line-height: 30px;\n    font-style: normal;\n    padding: 2px 0;\n    color: #000;\n  }\n</style>\n\n<div id=\"glz_custom_fields_help\">\n  <h1>glz_custom_fields, limitless pimped custom fields</h1>\n\n  <p><strong>If you want to submit bug reports and feature requests, please visit <a href=\"http://github.com/gerhard/glz_custom_fields_public\" title=\"glz_custom_fields on GitHub\">glz_custom_fields of GitHub</a></strong>. <br />There is also a handy section on <a href=\"http://wiki.github.com/gerhard/glz_custom_fields_public/\" title=\"glz_custom_fields wiki\">glz_custom_fields tips and tricks</a>.</p>\n  \n  <h2>Time &amp; Date Pickers</h2>\n  <p>They are pretty straightforward to use, no explanation needed. To set the required Javascript and styling properly, please refer to the <strong>INSTALL</strong> file that came with this plugin.</p>\n  \n  <h2>Custom Scripts</h2>\n  <p>This is a rather complex and long sought for piece of functionality, please refer to the <strong>my_image.php</strong> file which contains inline explanations on how they should be used. The file came with the plugin, in the scripts/glz_custom_fields folder.</p>\n  \n  <h2>Default values</h2>\n  <p>You can now define a single default value by adding curly brackets around a value like this <code>{default value}</code>. Support for multiple ones will be implemented at some point.</p>\n  \n  <h2>Ranges</h2>\n  <p>If you want to define ranges, create a new custom field with the following name e.g. <code>Price range &amp;pound;(after)</code></p>\n  <ul>\n  <li><code>range</code> - this is really important and <strong>must</strong> be present for the range to work correctly</li>\n  <li><code>&amp;pound;</code> - don\'t use straight symbols (like &euro; or &pound;) but entity ones e.g. &amp;pound; &amp; &amp;euro; $ and &amp;cent are valid symbols.</li>\n  <li><code>(after)</code> - don\'t leave any spaces after e.g. $ and (after). This basically says where to add the measuring unit (be it a currency or something like m<sup>3</sup> etc.) - <code>(before)</code> is default.</li>\n  </ul>\n\n  <p>Ranges are defined 10-20, 21-30 etc. (no measuring units - they get pulled from the custom set name).</p>\n\n  <h2>Support</h2>\n  <p>If anything goes wrong or you discover a bug:</p>\n  <ol>\n    <li>submit it on <a href=\"http://github.com/gerhard/glz_custom_fields_public/issues\" title=\"glz_custom_fields_public issues\">GitHub</a></li>\n    <li>look for help in the forum, <a href=\"http://forum.textpattern.com/viewtopic.php?id=23996\">glz_custom_fields thread</a></li>\n    <li>ping me via <a href=\"http://www.twitter.com/gerhardlazu\">Twitter</a>. I\'m using it around the clock, it\'s great for short messages!</li>\n    <li>drop a line to <a href=\"mailto:gerhard@lazu.co.uk?Subject:glz_custom_fields needs your attention\">gerhard@lazu.co.uk</a> (sometimes things can get really hectic on my end, please be patient)</li>\n  </ol>\n  <p>If you have lost your glz_custom_fields copy, get another one from <a href=\"http://groups.google.com/group/glz_custom_fields\">glz_custom_fields Google Group</a>. This is a private group, only people that have donated have access to it. I would appreciate if you would post queries on the public Textpattern forum, I want to avoid having to follow 2 places for support issues. Thanks!</p>\n</div>','# glz_custom_fields v1.2.4\n# Unlimited, super special custom fields.\n#\n# Gerhard Lazu\n# http://gerhardlazu.com\n#\n# Contributors: Randy Levine, Sam Weiss, Luca Botti, Manfre, Vladimir Siljkovic, Julian Reisenberger, Steve Dickinson, Stef Dawson, Jean-Pol Dupont\n# Minimum requirements: Textpattern 4.2.0\n\n// Including helper files. If we can\'t have classes, we will use includes\n\n\n// -------------------------------------------------------------\n// messages that will be available throughout this plugin\nfunction glz_custom_fields_gTxt($get, $atts = array()) {\n  $lang = array(\n    \'no_name\'           => \'Ooops! <strong>custom set</strong> must have a name\',\n    \'deleted\'           => \'<strong>{custom_set_name}</strong> was deleted\',\n    \'reset\'             => \'<strong>{custom_set_name}</strong> was reset\',\n    \'created\'           => \'<strong>{custom_set_name}</strong> was created\',\n    \'updated\'           => \'<strong>{custom_set_name}</strong> was updated\',\n    \'exists\'            => \'Ooops! <strong>{custom_set_name}</strong> already exists\',\n    \'doesnt_exist\'      => \'Ooops! <strong>{custom_set_name}</strong> is not set\',\n    \'field_problems\'    => \'Ooops! <strong>{custom_set_name}</strong> has some problems. <a href=\"?event=glz_custom_fields\">Go fix it</a>.\',\n    \'custom_set\'        => \'Text Input\', # custom sets in TXP 4.2.0 are by type custom_set by default...\n    \'text_input\'        => \'Text Input\',\n    \'select\'            => \'Select\',\n    \'multi-select\'      => \'Multi-Select\',\n    \'textarea\'          => \'Textarea\',\n    \'checkbox\'          => \'Checkbox\',\n    \'radio\'             => \'Radio\',\n    \'date-picker\'       => \'Date Picker\',\n    \'time-picker\'       => \'Time Picker\',\n    \'custom-script\'     => \'Custom Script\',\n    \'type_not_supported\'=> \'Type not supported\',\n    \'no_do\'             => \'Ooops! No action specified for method, abort.\',\n    \'not_specified\'     => \'Ooops! {what} is not specified\',\n    \'searchby_not_set\'  => \'<strong>searcby</strong> cannot be left blank\',\n    \'jquery_missing\'    => \'Upgrade TXP to at least 4.0.5 or put <strong>jquery.js</strong> in your /textpattern folder. <a href=\"http://jquery.com\" title=\"jQuery website\">jQuery website</a>\',\n    \'check_path\'        => \'Make sure all your paths are correct. Check <strong>config.php</strong> and the Admin tab (mainly Advanced).\',\n    \'no_articles_found\' => \'No articles with custom fields have been found.\',\n    \'migration_success\' => \'Migrating custom fields was successful\',\n    \'migration_skip\'    => \'<strong>custom_fields</strong> table already has data in it, migration skipped.\',\n    \'search_section_created\'  => \'<strong>search</strong> section has been created\',\n    \'custom_sets_all_input\'   => \'All custom sets have been set back to input\',\n    \'preferences_updated\'     => \'Plugin preferences have been updated\',\n    \'not_found\'         => \'Ooops! <strong>{file}</strong> cannot be found, check path\',\n    \'not_callable\'      => \'Ooops! <strong>{function}()</strong> cannot be called. Ensure <strong>{file}</strong> can be executed.\'\n  );\n\n  $out = ( strstr($lang[$get], \"Ooops!\") ) ? // Ooops! would appear 0 in the string...\n      \"<span class=\\\"red\\\">{$lang[$get]}</span>\" :\n      $lang[$get];\n\n  return strtr($out, $atts);\n}\n\n\n\n\n\n\n// -------------------------------------------------------------\n// I would do this through a factory class, but some folks are still running PHP4...\nfunction glz_custom_fields_MySQL($do, $name=\'\', $table=\'\', $extra=\'\') {\n  if ( !empty($do) ) {\n    switch ( $do ) {\n      case \'all\':\n        return glz_all_custom_sets();\n        break;\n\n      case \'values\':\n        return glz_values_custom_field($name, $extra);\n        break;\n\n      case \'all_values\' :\n        return glz_all_existing_custom_values($name, $extra);\n        break;\n\n      case \'article_customs\':\n        return glz_article_custom_fields($name, $extra);\n        break;\n\n      case \'next_custom\':\n        return glz_next_empty_custom();\n        break;\n\n      case \'new\':\n        glz_new_custom_field($name, $table, $extra);\n        glz_custom_fields_update_count();\n        break;\n\n      case \'update\':\n        return glz_update_custom_field($name, $table, $extra);\n        break;\n\n      case \'reset\':\n        return glz_reset_custom_field($name, $table, $extra);\n        break;\n\n      case \'delete\':\n        glz_delete_custom_field($name, $table);\n        glz_custom_fields_update_count();\n        break;\n\n      case \'check_migration\':\n        return glz_check_migration();\n        break;\n\n      case \'mark_migration\':\n        return glz_mark_migration();\n        break;\n\n      case \'custom_set_exists\':\n        return glz_check_custom_set_exists($name);\n        break;\n\n      case \'plugin_preferences\':\n        return glz_plugin_preferences($name);\n        break;\n\n      case \'update_plugin_preferences\':\n        return glz_update_plugin_preferences($name);\n        break;\n    }\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'no_do\'));\n}\n\n\nfunction glz_all_custom_sets() {\n  $all_custom_sets = getRows(\"\n    SELECT\n      `name` AS custom_set,\n      `val` AS name,\n      `position`,\n      `html` AS type\n    FROM\n      `\".PFX.\"txp_prefs`\n    WHERE\n      `event`=\'custom\'\n    ORDER BY\n      `position`\n  \");\n\n  foreach ( $all_custom_sets as $custom_set ) {\n    $out[$custom_set[\'custom_set\']] = array(\n      \'name\'      => $custom_set[\'name\'],\n      \'position\'  => $custom_set[\'position\'],\n      \'type\'      => $custom_set[\'type\']\n    );\n  }\n\n  return $out;\n}\n\n\nfunction glz_values_custom_field($name, $extra) {\n  global $prefs;\n\n  if ( is_array($extra) ) {\n    extract($extra);\n\n    if ( !empty($name) ) {\n      switch ( $prefs[\'values_ordering\'] ) {\n        case \"ascending\":\n          $orderby = \"value ASC\";\n          break;\n        case \"descending\":\n          $orderby = \"value DESC\";\n          break;\n        default:\n          $orderby = \"id ASC\";\n      }\n\n\n      $arr_values = getThings(\"\n        SELECT\n          `value`\n        FROM\n          `\".PFX.\"custom_fields`\n        WHERE\n          `name` = \'{$name}\'\n        ORDER BY\n          {$orderby}\n      \");\n\n      if ( count($arr_values) > 0 ) {\n        // decode all special characters e.g. \", & etc. and use them for keys\n        foreach ( $arr_values as $key => $value )\n          $arr_values_formatted[glz_return_clean_default(htmlspecialchars($value))] = stripslashes($value);\n\n        // if this is a range, format ranges accordingly\n        return glz_format_ranges($arr_values_formatted, $custom_set_name);\n      }\n    }\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_all_existing_custom_values($name, $extra) {\n  if ( is_array($extra) ) {\n    extract(lAtts(array(\n      \'custom_set_name\'   => \"\",\n      \'status\'            => 4\n    ),$extra));\n\n    // we might want to check the custom field values for all articles - think initial migration\n    $status_condition = ($status == 0) ? \"<> \'\'\" : \"= \'$status\'\";\n\n    if ( !empty($name) ) {\n      $arr_values = getThings(\"\n        SELECT DISTINCT\n          `$name`\n        FROM\n          `\".PFX.\"textpattern`\n        WHERE\n          `Status` $status_condition\n        AND\n          `$name` <> \'\'\n        ORDER BY\n          `$name`\n        \");\n\n      // trim all values\n      foreach ( $arr_values as $key => $value )\n        $arr_values[$key] = trim($value);\n\n      // DEBUG\n      // dmp($arr_values);\n\n      // prepare our array for checking. We need a single string to check for | instances - seems quickest.\n      $values_check = join(\'::\', $arr_values);\n\n      // DEBUG\n      // dmp($values_check);\n\n      // check if some of the values are multiple ones\n      if ( strstr($values_check, \'|\') ) {\n        // initialize $out\n        $out = array();\n        // put all values in an array\n        foreach ( $arr_values as $value ) {\n          $arr_values = explode(\'|\', $value);\n          $out = array_merge($out, $arr_values);\n        }\n        // keep only the unique ones\n        $out = array_unique($out);\n        // keys and values need to be the same\n        $out = php4_array_combine($out, $out);\n      }\n\n      // check if this is a range\n      else if ( strstr($values_check, \'-\') && strstr($custom_set_name, \'range\') )\n        // keys won\'t have the unit ($, £, m<sup>3</sup>, etc.) values will\n        $out = glz_format_ranges($arr_values, $custom_set_name);\n      else\n        // keys and values need to be the same\n        $out = php4_array_combine($arr_values, $arr_values);\n\n      // calling stripslashes on all array values\n      array_map(\'glz_array_stripslashes\', $out);\n\n      return $out;\n    }\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_article_custom_fields($name, $extra) {\n  if ( is_array($extra) ) {\n    // see what custom fields we need to query for\n    foreach ( $extra as $custom => $custom_set )\n      $select[] = glz_custom_number($custom);\n\n    // prepare the select elements\n    $select = implode(\',\', $select);\n\n    $arr_article_customs = getRow(\"\n      SELECT\n        $select\n      FROM\n        `\".PFX.\"textpattern`\n      WHERE\n        `ID`=\'$name\'\n    \");\n\n    return $arr_article_customs;\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_new_custom_field($name, $table, $extra) {\n  if ( is_array($extra) ) {\n    extract($extra);\n    // DRYing up, we\'ll be using this variable quiet often\n    $custom_set = ( isset($custom_field_number) ) ?\n      \"custom_{$custom_field_number}_set\" :\n      $custom_set;\n\n    if ( ($table == PFX.\"txp_prefs\") ) {\n      // if this is a new field without a position, use the $custom_field_number\n      if (empty($custom_set_position)) $custom_set_position = $custom_field_number;\n      $query = \"\n        INSERT INTO\n          `\".PFX.\"txp_prefs` (`prefs_id`, `name`, `val`, `type`, `event`, `html`, `position`)\n        VALUES\n          (\'1\', \'{$custom_set}\', \'{$name}\', \'1\', \'custom\', \'{$custom_set_type}\', {$custom_set_position})\n      \";\n    }\n    else if ( $table == PFX.\"txp_lang\" ) {\n      $query = \"\n        INSERT INTO\n          `\".PFX.\"txp_lang` (`id`,`lang`,`name`,`event`,`data`,`lastmod`)\n        VALUES\n          (\'\',\'{$lang}\',\'{$custom_set}\',\'prefs\',\'{$name}\',now())\n      \";\n    }\n    else if ( $table == PFX.\"textpattern\" ) {\n      $column_type = ( $custom_set_type == \"textarea\" ) ? \"TEXT\" : \"VARCHAR(255)\";\n      $query = \"\n        ALTER TABLE\n          `\".PFX.\"textpattern`\n        ADD\n          `custom_{$custom_field_number}` {$column_type} NOT NULL DEFAULT \'\'\n      \";\n    }\n    else if ( $table == PFX.\"custom_fields\" ) {\n      $arr_values = array_unique(array_filter(explode(\"\\r\\n\", $value), \'glz_arr_empty_values\'));\n\n      if ( is_array($arr_values) && !empty($arr_values) ) {\n        $size_arr_values = count($arr_values);\n        $insert = \'\';\n        foreach ( $arr_values as $key => $value ) {\n          // don\'t insert empty values\n          if ( !empty($value) )\n            // make sure special characters are escaped before inserting them in the database\n            $value = addslashes(addslashes(trim($value)));\n            // if this is the last value, query will have to be different\n            $insert .= ($key+1 != $size_arr_values ) ?\n              \"(\'{$custom_set}\',\'{$value}\'), \" :\n              \"(\'{$custom_set}\',\'{$value}\')\";\n        }\n        $query = \"\n          INSERT INTO\n            `\".PFX.\"custom_fields` (`name`,`value`)\n          VALUES\n            {$insert}\n        \";\n      }\n    }\n    if ( isset($query) && !empty($query) )\n      safe_query($query);\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_update_custom_field($name, $table, $extra) {\n  if ( is_array($extra) )\n    extract($extra);\n\n  if ( ($table == PFX.\"txp_prefs\") ) {\n    safe_query(\"\n      UPDATE\n        `\".PFX.\"txp_prefs`\n      SET\n        `val` = \'{$custom_set_name}\',\n        `html` = \'{$custom_set_type}\',\n        `position` = \'{$custom_set_position}\'\n      WHERE\n        `name`=\'{$name}\'\n    \");\n  }\n  else if ( ($table == PFX.\"textpattern\") ) {\n    $column_type = ( $custom_set_type == \"textarea\" ) ? \"TEXT\" : \"VARCHAR(255)\";\n    safe_query(\"\n      ALTER TABLE\n        `\".PFX.\"textpattern`\n      MODIFY\n        `{$custom_field}` {$column_type} NOT NULL DEFAULT \'\'\n    \");\n  }\n}\n\n\nfunction glz_reset_custom_field($name, $table, $extra) {\n  if ( is_array($extra) )\n    extract($extra);\n\n  if ( $table == PFX.\"txp_prefs\" ) {\n    safe_query(\"\n      UPDATE\n        `\".PFX.\"txp_prefs`\n      SET\n        `val` = \'\',\n        `html` = \'text_input\'\n      WHERE\n        `name`=\'{$name}\'\n    \");\n  }\n  else if ( $table == PFX.\"textpattern\" ) {\n    safe_query(\"UPDATE `\".PFX.\"textpattern` SET `{$name}` = \'\'\");\n    safe_query(\"ALTER TABLE `\".PFX.\"textpattern` MODIFY `{$custom_field}` VARCHAR(255) NOT NULL DEFAULT \'\'\");\n  }\n}\n\n\nfunction glz_delete_custom_field($name, $table) {\n  // remember, custom fields under 10 MUST NOT be deleted\n  if ( glz_custom_digit($name) > 10 ) {\n    if ( in_array($table, array(PFX.\"txp_prefs\", PFX.\"txp_lang\", PFX.\"custom_fields\")) ) {\n      $query = \"\n        DELETE FROM\n          `{$table}`\n        WHERE\n          `name`=\'{$name}\'\n      \";\n    }\n    else if ( $table == PFX.\"textpattern\" ) {\n      $query = \"\n        ALTER TABLE\n          `\".PFX.\"textpattern`\n        DROP\n          `{$name}`\n      \";\n    }\n    safe_query($query);\n  }\n  else {\n    if ( $table == PFX.\"txp_prefs\" )\n      glz_custom_fields_MySQL(\"reset\", $name, $table);\n    else if ( ($table == PFX.\"custom_fields\") ) {\n      safe_query(\"\n        DELETE FROM\n          `{$table}`\n        WHERE\n          `name`=\'{$name}\'\n      \");\n    }\n  }\n}\n\n\n// -------------------------------------------------------------\n// checks if custom_fields table has any values in it\nfunction glz_check_migration() {\n  return getThing(\"\n    SELECT\n      COUNT(*)\n    FROM\n      `\".PFX.\"custom_fields`\n  \");\n}\n\n\n// -------------------------------------------------------------\n// make a note of glz_custom_fields migration in txp_prefs\nfunction glz_mark_migration() {\n  set_pref(\"migrated\", \"1\", \"glz_custom_f\");\n}\n\n\n// -------------------------------------------------------------\n// check if one of the special custom fields exists\nfunction glz_check_custom_set_exists($name) {\n  if ( !empty($name) ) {\n    return getThing(\"\n      SELECT\n        `name`, `val`\n      FROM\n        `\".PFX.\"txp_prefs`\n      WHERE\n        `html` = \'{$name}\'\n      AND\n        `name` LIKE \'custom_%\'\n      ORDER BY\n        `name`\n    \");\n  }\n}\n\n\n// -------------------------------------------------------------\n// updates max_custom_fields\nfunction glz_custom_fields_update_count() {\n  set_pref(\'max_custom_fields\', safe_count(\"txp_prefs\", \"event=\'custom\'\"));\n}\n\n// -------------------------------------------------------------\n// returns all plugin preferences\nfunction glz_plugin_preferences($arr_preferences) {\n	$r = safe_rows_start(\'name, val\', \'txp_prefs\', \"event = \'glz_custom_f\'\");\n	if ($r) {\n		while ($a = nextRow($r)) {\n			$out[$a[\'name\']] = stripslashes($a[\'val\']);\n		}\n	}\n  return $out;\n}\n\n// -------------------------------------------------------------\n// updates all plugin preferences\nfunction glz_update_plugin_preferences($arr_preferences) {\n  // die(dmp($arr_preferences));\n  foreach ($arr_preferences as $preference => $value) {\n    // if there is a preference which doesn\'t exist, create it\n    if ( !isset($prefs[$preference]) )\n      set_pref($preference, addslashes(addslashes(trim($value))), \"glz_custom_f\", 10); // 10 so that it won\'t appear under TXP\'s prefs tab\n  }\n}\n\n\n\n\n\n\n// this function doesn\'t seem to be currently used, remove or make it useful\nfunction glz_next_empty_custom() {\n  global $all_custom_sets;\n\n  foreach ( $all_custom_sets as $custom => $custom_set ) {\n    if ( empty($custom_set[\'name\']) )\n      return $custom;\n  }\n}\n\n\n// -------------------------------------------------------------\n// edit/delete buttons in custom_fields table require a form each\nfunction glz_form_buttons($action, $value, $custom_set, $custom_set_name, $custom_set_type, $custom_set_position, $onsubmit=\'\') {\n  $onsubmit = ($onsubmit) ?\n    \'onsubmit=\"\'.$onsubmit.\'\"\' :\n    \'\';\n\n  return\n    \'<form method=\"post\" action=\"index.php\" \'.$onsubmit.\'>\n      <input name=\"custom_set\" value=\"\'.$custom_set.\'\" type=\"hidden\" />\n      <input name=\"custom_set_name\" value=\"\'.$custom_set_name.\'\" type=\"hidden\" />\n      <input name=\"custom_set_type\" value=\"\'.$custom_set_type.\'\" type=\"hidden\" />\n      <input name=\"custom_set_position\" value=\"\'.$custom_set_position.\'\" type=\"hidden\" />\n      <input name=\"event\" value=\"glz_custom_fields\" type=\"hidden\" />\n      <input name=\"\'.$action.\'\" value=\"\'.$value.\'\" type=\"submit\" />\n    </form>\';\n}\n\n\n// -------------------------------------------------------------\n// the types our custom fields can take\nfunction glz_custom_set_types() {\n  return array(\n    \'normal\' => array(\n      \'text_input\',\n      \'checkbox\',\n      \'radio\',\n      \'select\',\n      \'multi-select\',\n      \'textarea\'),\n    \'special\' => array(\n      \'date-picker\',\n      \'time-picker\',\n      \'custom-script\')\n  );\n}\n\n\n// -------------------------------------------------------------\n// outputs only custom fields that have been set, i.e. have a name assigned to them\nfunction glz_check_custom_set($all_custom_sets, $step) {\n  $out = array();\n\n  foreach ($all_custom_sets as $key => $custom_field) {\n    if (!empty($custom_field[\'name\'])) {\n      if ( ($step == \"excerpt\") && ($custom_field[\'type\'] == \"textarea\") )\n        $out[$key] = $custom_field;\n      else if ( ($step == \"custom_fields\") && ($custom_field[\'type\'] != \"textarea\") ) {\n        $out[$key] = $custom_field;\n      }\n    }\n  }\n\n  return $out;\n}\n\n\n// -------------------------------------------------------------\n// removes { } from values which are marked as default\nfunction glz_return_clean_default($value) {\n  $pattern = \"/^.*\\{(.*)\\}.*/\";\n\n  return preg_replace($pattern, \"$1\", $value);\n}\n\n\n// -------------------------------------------------------------\n// return our default value from all custom_field values\nfunction glz_default_value($all_values) {\n  if ( is_array($all_values) ) {\n    preg_match(\"/(\\{.*\\})/\", join(\" \", $all_values), $default);\n    return ( (!empty($default) && $default[0]) ? $default[0] : \'\');\n  }\n}\n\n\n// -------------------------------------------------------------\n// calling the above function in an array context\nfunction glz_clean_default_array_values(&$value) {\n  $value = glz_return_clean_default($value);\n}\n\n\n// -------------------------------------------------------------\n// custom_set without \"_set\" e.g. custom_1_set => custom_1\n// or custom set formatted for IDs e.g. custom-1\nfunction glz_custom_number($custom_set, $delimiter=\"_\") {\n  $custom_field = substr($custom_set, 0, -4);\n\n  if ($delimiter != \"_\")\n    $custom_field = str_replace(\"_\", $delimiter, $custom_field);\n\n  return $custom_field;\n}\n\n\n// -------------------------------------------------------------\n// custom_set digit e.g. custom_1_set => 1\nfunction glz_custom_digit($custom_set) {\n  $out = explode(\"_\", $custom_set);\n  // $out[0] will always be custom\n  return $out[1];\n}\n\n\n// -------------------------------------------------------------\n// removes empty values from arrays - used for new custom fields\nfunction glz_arr_empty_values($value) {\n  if ( !empty($value) )\n    return $value;\n}\n\n\n// -------------------------------------------------------------\n// returns the custom set from a custom set name e.g. \"Rating\" gives us custom_1_set\nfunction glz_get_custom_set($value) {\n  global $all_custom_sets;\n\n  // go through all custom fields and see if the one we\'re looking for exists\n  foreach ( $all_custom_sets as $custom => $custom_set ) {\n    if ( $custom_set[\'name\'] == $value )\n      return $custom;\n  }\n  // if it doesn\'t, return error message\n  trigger_error(glz_custom_fields_gTxt(\'doesnt_exist\', array(\'{custom_set_name}\' => $value)));\n}\n\n\n// -------------------------------------------------------------\n// get the article ID, EVEN IF it\'s newly saved\nfunction glz_get_article_id() {\n  return ( !empty($GLOBALS[\'ID\']) ?\n    $GLOBALS[\'ID\'] :\n    gps(\'ID\') );\n}\n\n\n// -------------------------------------------------------------\n// helps with range formatting - just DRY\nfunction glz_format_ranges($arr_values, $custom_set_name) {\n  //initialize $out\n  $out = \'\';\n  foreach ( $arr_values as $key => $value ) {\n    $out[$key] = ( strstr($custom_set_name, \'range\') ) ?\n      glz_custom_fields_range($value, $custom_set_name) :\n      $value;\n  }\n  return $out;\n}\n\n\n// -------------------------------------------------------------\n// acts as a callback for the above function\nfunction glz_custom_fields_range($custom_value, $custom_set_name) {\n  // last part of the string will be the range unit (e.g. $, &pound;, m<sup>3</sup> etc.)\n  $nomenclature = array_pop(explode(\' \', $custom_set_name));\n\n  // see whether range unit should go after\n  if ( strstr($nomenclature, \'(after)\') ) {\n    // trim \'(after)\' from the measuring unit\n    $nomenclature = substr($nomenclature, 0, -7);\n    $after = 1;\n  }\n\n  // check whether it\'s a range or single value\n  $arr_value = explode(\'-\', $custom_value);\n  if ( is_array($arr_value) ) {\n    // initialize $out\n    $out = \'\';\n    foreach ( $arr_value as $value ) {\n      // check whether nomenclature goes before or after\n      $out[] = ( !isset($after) ) ?\n        $nomenclature.number_format($value) :\n        number_format($value).$nomenclature;\n    }\n    return implode(\'-\', $out);\n  }\n  // our range is a single value\n  else {\n    // check whether nomenclature goes before or after\n    return ( !isset($after) ) ?\n      $nomenclature.number_format($value) :\n      number_format($value).$nomenclature;\n  }\n}\n\n\n// -------------------------------------------------------------\n// returns the next available number for custom set\nfunction glz_custom_next($arr_custom_sets) {\n  $arr_extra_custom_sets = array();\n  foreach ( array_keys($arr_custom_sets) as $extra_custom_set) {\n    $arr_extra_custom_sets[] = glz_custom_digit($extra_custom_set);\n  }\n  // order the array\n  sort($arr_extra_custom_sets);\n\n  for ( $i=0; $i < count($arr_extra_custom_sets); $i++ ) {\n    if ($arr_extra_custom_sets[$i] > $i+1)\n      return $i+1;\n  }\n\n  return count($arr_extra_custom_sets)+1;\n}\n\n\n// -------------------------------------------------------------\n// checks if the custom field name isn\'t already taken\nfunction glz_check_custom_set_name($arr_custom_fields, $custom_set_name, $custom_set=\'\') {\n  foreach ( $arr_custom_fields as $custom => $arr_custom_set ) {\n    if ( ($custom_set_name == $arr_custom_set[\'name\']) && (!empty($custom_set) && $custom_set != $custom) )\n      return TRUE;\n  }\n\n  return FALSE;\n}\n\n\n// -------------------------------------------------------------\n// formats the custom set output based on its type\nfunction glz_format_custom_set_by_type($custom, $custom_id, $custom_set_type, $arr_custom_field_values, $custom_value = \"\", $default_value = \"\") {\n  if ( is_array($arr_custom_field_values) )\n    $arr_custom_field_values = array_map(\'glz_array_stripslashes\', $arr_custom_field_values);\n\n  switch ( $custom_set_type ) {\n    // these are the normal custom fields\n    case \"text_input\":\n      return array(\n        fInput(\"text\", $custom, $custom_value, \"edit\", \"\", \"\", \"22\", \"\", $custom_id),\n        \'glz_custom_field\'\n      );\n\n    case \"select\":\n      return array(\n        glz_selectInput($custom, $custom_id, $arr_custom_field_values, $custom_value, $default_value),\n        \'glz_custom_select_field\'\n      );\n\n    case \"multi-select\":\n      return array(\n        glz_selectInput($custom, $custom_id, $arr_custom_field_values, $custom_value, $default_value, 1),\n        \'glz_custom_multi-select_field\'\n      );\n\n    case \"checkbox\":\n      return array(\n        glz_checkbox($custom, $arr_custom_field_values, $custom_value, $default_value),\n        \'glz_custom_checkbox_field\'\n      );\n\n    case \"radio\":\n      return array(\n        glz_radio($custom, $custom_id, $arr_custom_field_values, $custom_value, $default_value),\n        \'glz_custom_radio_field\'\n      );\n\n    case \"textarea\":\n      return array(\n        text_area($custom, 100, 500, $custom_value, $custom_id),\n        \'glz_text_area_field\'\n      );\n\n    // here start the special custom fields, might need to refactor the return, starting to repeat itself\n    case \"date-picker\":\n      return array(\n        fInput(\"text\", $custom, $custom_value, \"edit date-picker\", \"\", \"\", \"22\", \"\", $custom_id),\n        \'glz_custom_date-picker_field clearfix\'\n      );\n    \n    case \"time-picker\":\n      return array(\n        fInput(\"text\", $custom, $custom_value, \"edit time-picker\", \"\", \"\", \"22\", \"\", $custom_id),\n        \'glz_custom_time-picker_field\'\n      );\n    \n    case \"custom-script\":\n      return array(\n        glz_custom_script(reset($arr_custom_field_values), $custom, $custom_id, $custom_value),\n        \'glz_custom_field_script\'\n      );\n\n    // a type has been passed that is not supported yet\n    default:\n      return array(\n        glz_custom_fields_gTxt(\'type_not_supported\'),\n        \'glz_custom_field\'\n      );\n  }\n}\n\n\n// -------------------------------------------------------------\n// had to duplicate the default selectInput() because trimming \\t and \\n didn\'t work + some other mods & multi-select\nfunction glz_selectInput($name = \'\', $id = \'\', $arr_values = \'\', $custom_value = \'\', $default_value = \'\', $multi = \'\') {\n  if ( is_array($arr_values) ) {\n    global $prefs;\n    $out = array();\n\n    // if there is no custom_value coming from the article, let\'s use our default one\n    if ( empty($custom_value) )\n      $custom_value = $default_value;\n\n    foreach ($arr_values as $key => $value) {\n      $selected = glz_selected_checked(\'selected\', $key, $custom_value, $default_value);\n      $out[] = \"<option value=\\\"$key\\\"{$selected}>$value</option>\";\n    }\n\n    // we\'ll need the extra attributes as well as a name that will produce an array\n    if ($multi) {\n      $multi = \' multiple=\"multiple\" size=\"\'.$prefs[\'multiselect_size\'].\'\"\';\n      $name .= \"[]\";\n    }\n\n    return \"<select id=\\\"\".glz_idify($id).\"\\\" name=\\\"$name\\\" class=\\\"list\\\"$multi>\".\n      ($default_value ? \'\' : \"<option value=\\\"\\\"$selected>&nbsp;</option>\").\n      ( $out ? join(\'\', $out) : \'\').\n      \"</select>\";\n  }\n  else\n    return glz_custom_fields_gTxt(\'field_problems\', array(\'{custom_set_name}\' => $name));\n}\n\n\n// -------------------------------------------------------------\n// had to duplicate the default checkbox() to keep the looping in here and check against existing value/s\nfunction glz_checkbox($name = \'\', $arr_values = \'\', $custom_value = \'\', $default_value = \'\') {\n  if ( is_array($arr_values) ) {\n    $out = array();\n\n    // if there is no custom_value coming from the article, let\'s use our default one\n    if ( empty($custom_value) )\n      $custom_value = $default_value;\n\n    foreach ( $arr_values as $key => $value ) {\n      $checked = glz_selected_checked(\'checked\', $key, $custom_value);\n\n      // Putting an additional span around the input and label combination so the two can be floated together as a pair for left-right, left-right,... arrangement of checkboxes and radio buttons. Thanks Julian!\n      $out[] = \"<span><input type=\\\"checkbox\\\" name=\\\"{$name}[]\\\" value=\\\"$key\\\" class=\\\"checkbox\\\" id=\\\"\".glz_idify($key).\"\\\"{$checked} /><label for=\\\"\".glz_idify($key).\"\\\">$value</label></span><br />\";\n    }\n\n    return join(\'\', $out);\n  }\n  else\n    return glz_custom_fields_gTxt(\'field_problems\', array(\'{custom_set_name}\' => $name));\n}\n\n\n// -------------------------------------------------------------\n// had to duplicate the default radio() to keep the looping in here and check against existing value/s\nfunction glz_radio($name = \'\', $id = \'\', $arr_values = \'\', $custom_value = \'\', $default_value = \'\') {\n  if ( is_array($arr_values) ) {\n    $out = array();\n\n    // if there is no custom_value coming from the article, let\'s use our default one\n    if ( empty($custom_value) )\n      $custom_value = $default_value;\n\n    foreach ( $arr_values as $key => $value ) {\n      $checked = glz_selected_checked(\'checked\', $key, $custom_value);\n\n      // Putting an additional span around the input and label combination so the two can be floated together as a pair for left-right, left-right,... arrangement of checkboxes and radio buttons. Thanks Julian!\n      $out[] = \"<span><input type=\\\"radio\\\" name=\\\"$name\\\" value=\\\"$key\\\" class=\\\"radio\\\" id=\\\"{$id}_\".glz_idify($key).\"\\\"{$checked} /><label for=\\\"{$id}_\".glz_idify($key).\"\\\">$value</label></span><br />\";\n    }\n\n    return join(\'\', $out);\n  }\n  else\n    return glz_custom_fields_gTxt(\'field_problems\', array(\'{custom_set_name}\' => $name));\n}\n\n\n// -------------------------------------------------------------\n// checking if this custom field has selected or checked values\nfunction glz_selected_checked($nomenclature, $value, $custom_value = \'\') {\n  // we\'re comparing against a key which is a \"clean\" value\n  $custom_value = htmlspecialchars($custom_value);\n\n  // make an array if $custom_value contains multiple values\n  if ( strpos($custom_value, \'|\') )\n    $arr_custom_value = explode(\'|\', $custom_value);\n\n  if ( isset($arr_custom_value) )\n    $out = ( in_array($value, $arr_custom_value) ) ? \" $nomenclature=\\\"$nomenclature\\\"\" : \"\";\n  else\n    $out = ($value == $custom_value) ? \" $nomenclature=\\\"$nomenclature\\\"\" : \"\";\n\n  return $out;\n}\n\n\n//-------------------------------------------------------------\n// button gets more consistent styling across browsers rather than input type=\"submit\"\n// included in this plugin until in makes it into TXP - if that ever happens...\nfunction glz_fButton($type, $name, $contents=\'Submit\', $value, $class=\'\', $id=\'\', $title=\'\', $onClick=\'\', $disabled = false) {\n  $o  = \'<button type=\"\'.$type.\'\" name=\"\'.$name.\'\"\';\n  $o .= \' value=\"\'.htmlspecialchars($value).\'\"\';\n  $o .= ($class)    ? \' class=\"\'.$class.\'\"\' : \'\';\n  $o .= ($id)       ? \' id=\"\'.$id.\'\"\' : \'\';\n  $o .= ($title)    ? \' title=\"\'.$title.\'\"\' : \'\';\n  $o .= ($onClick)  ? \' onclick=\"\'.$onClick.\'\"\' : \'\';\n  $o .= ($disabled) ? \' disabled=\"disabled\"\' : \'\';\n  $o .= \'>\';\n  $o .= $contents;\n  $o .= \'</button>\';\n  return $o;\n}\n\n\n//-------------------------------------------------------------\n// evals a PHP script and displays output right under the custom field label\nfunction glz_custom_script($script, $custom, $custom_id, $custom_value) {\n  if ( is_file($script) ) {\n    include($script);\n    $custom_function = basename($script, \".php\");\n    if ( is_callable($custom_function) ) {\n      return call_user_func_array($custom_function, array($custom, $custom_id, $custom_value));\n    }\n    else\n      return glz_custom_fields_gTxt(\'not_callable\', array(\'{function}\' => $custom_function, \'{file}\' => $script));\n  }\n  else\n    return glz_custom_fields_gTxt(\'not_found\', array(\'{file}\' => $script));\n\n}\n\n\n// -------------------------------------------------------------\n// PHP4 doesn\'t come with array_combine... Thank you redbot!\nfunction php4_array_combine($keys, $values) {\n  $result = array(); // initializing the array\n\n  foreach ( array_map(null, $keys, $values) as $pair ) {\n    $result[$pair[0]] = $pair[1];\n  }\n\n  return $result;\n}\n\n\n// -------------------------------------------------------------\n// converts all values into id safe ones\nfunction glz_idify($value) {\n  $patterns[0] = \"/\\s/\";\n  $replacements[0] = \"-\";\n  $patterns[1] = \"/[^a-zA-Z0-9\\-]/\";\n  $replacements[1] = \"\";\n\n  return preg_replace($patterns, $replacements, strtolower($value));\n}\n\n\n// -------------------------------------------------------------\n// strips slashes in arrays, used in conjuction with e.g. array_map\nfunction glz_array_stripslashes(&$value) {\n  return stripslashes($value);\n}\n\n\n// -------------------------------------------------------------\n// returns all sections/categories that are searchable\nfunction glz_all_searchable_sections_categories($type) {\n  $type = (in_array($type, array(\'category\', \'section\')) ? $type : \'section\');\n  $condition = \"\";\n\n  if ( $type == \"section\" )\n    $condition .= \"searchable=\'1\'\";\n  else\n    $condition .= \"name <> \'root\' AND type=\'article\'\";\n\n  $result = safe_rows(\'*\', \"txp_{$type}\", $condition);\n\n  $out = array();\n  foreach ($result as $value) {\n    $out[$value[\'name\']] = $value[\'title\'];\n  }\n\n  return $out;\n}\n\n// -------------------------------------------------------------\n// will leave only [A-Za-z0-9 ] in the string\nfunction glz_clean_string($string) {\n  if ($string)\n    return preg_replace(\'/[^A-Za-z0-9\\s\\_\\-]/\', \'\', $string);\n}\n\n\n\n\n\n// -------------------------------------------------------------\n// replaces the default custom fields under write tab\nfunction glz_custom_fields_replace($event, $step, $data, $rs) {\n  global $all_custom_sets, $date_picker;\n  // get all custom fields & keep only the ones which are set, filter by step\n  $arr_custom_fields = glz_check_custom_set($all_custom_sets, $step);\n\n  // DEBUG\n  // dmp($arr_custom_fields);\n\n  $out = \' \';\n\n  if ( is_array($arr_custom_fields) && !empty($arr_custom_fields) ) {\n    // get all custom fields values for this article\n    $arr_article_customs = glz_custom_fields_MySQL(\"article_customs\", glz_get_article_id(), \'\', $arr_custom_fields);\n\n    // DEBUG\n    // dmp($arr_article_customs);\n\n    if ( is_array($arr_article_customs) )\n      extract($arr_article_customs);\n\n    // let\'s see which custom fields are set\n    foreach ( $arr_custom_fields as $custom => $custom_set ) {\n      // get all possible/default value(s) for this custom set from custom_fields table\n      $arr_custom_field_values = glz_custom_fields_MySQL(\"values\", $custom, \'\', array(\'custom_set_name\' => $custom_set[\'name\']));\n\n      // DEBUG\n      // dmp($arr_custom_field_values);\n\n      //custom_set formatted for id e.g. custom_1_set => custom-1 - don\'t ask...\n      $custom_id = glz_custom_number($custom, \"-\");\n      //custom_set without \"_set\" e.g. custom_1_set => custom_1\n      $custom = glz_custom_number($custom);\n\n      // if current article holds no value for this custom field and we have no default value, make it empty\n      $custom_value = (!empty($$custom) ? $$custom : \'\');\n      // DEBUG\n      // dmp(\"custom_value: {$custom_value}\");\n\n      // check if there is a default value\n      // if there is, strip the { }\n      $default_value = glz_return_clean_default(glz_default_value($arr_custom_field_values));\n      // DEBUG\n      // dmp(\"default_value: {$default_value}\");\n\n      // now that we\'ve found our default, we need to clean our custom_field values\n      if (is_array($arr_custom_field_values))\n        array_walk($arr_custom_field_values, \"glz_clean_default_array_values\");\n\n      // DEBUG\n      // dmp($arr_custom_field_values);\n\n      // the way our custom field value is going to look like\n      list($custom_set_value, $custom_class) = glz_format_custom_set_by_type($custom, $custom_id, $custom_set[\'type\'], $arr_custom_field_values, $custom_value, $default_value);\n\n      // DEBUG\n      // dmp($custom_set_value);\n\n      $out .= graf(\n        \"<label for=\\\"$custom_id\\\">{$custom_set[\'name\']}</label><br />$custom_set_value\", \" class=\\\"$custom_class\\\"\"\n      );\n    }\n  }\n\n  // DEBUG\n  // dmp($out);\n\n  // if we\'re writing textarea custom fields, we need to include the excerpt as well\n  if ($step == \"excerpt\")\n    $out = $data.$out;\n\n  return $out;\n}\n\n\n// -------------------------------------------------------------\n// prep our custom fields for the db (watch out for multi-selects, checkboxes & radios, they might have multiple values)\nfunction glz_custom_fields_before_save() {\n  // keep only the custom fields\n  foreach ($_POST as $key => $value) {\n    //check for custom fields with multiple values e.g. arrays\n    if ( strstr($key, \'custom_\') && is_array($value) ) {\n      $value = implode($value, \'|\');\n      // feed our custom fields back into the $_POST\n      $_POST[$key] = $value;\n    }\n  }\n  // DEBUG\n  // dmp($_POST);\n}\n\n\n// -------------------------------------------------------------\n// adds the css & js we need\nfunction glz_custom_fields_css_js() {\n  global $glz_notice, $date_picker, $time_picker, $prefs;\n\n  // here come our custom stylesheetz\n  $css = <<<EOF\n<style type=\"text/css\" media=\"all\">\n/* - - - - - - - - - - - - - - - - - - - - -\n\n### TEXTPATTERN CUSTOM FIELDS ###\n\nTitle : glz_custom_fields stylesheet\nAuthor : Gerhard Lazu\nURL : http://www.gerhardlazu.com/\n\nCreated : 14th May 2007\nLast modified: 28th September 2009\n\n- - - - - - - - - - - - - - - - - - - - - */\n\n.clearfix:after {\n  content: \".\";\n  display: block;\n  clear: both;\n  visibility: hidden;\n  line-height: 0;\n  height: 0;\n}\n\n.clearfix {\n  display: inline-block;\n}\n\nhtml[xmlns] .clearfix {\n  display: block;\n}\n\n* html .clearfix {\n  height: 1%;\n}\n\n/* CLASSES\n-------------------------------------------------------------- */\n.green {\n  color: #6B3;\n}\n.red {\n  color: #C00;\n}\n.grey {\n  color: #777;\n}\n.left {\n  float: left;\n}\n.right {\n  float: right;\n}\n\n\n/* TABLE\n-------------------------------------------------------------- */\n.glz_custom_fields {\n  margin: 0 auto;\n  border: 1px solid #DDD;\n  width: 600px;\n}\n\n.glz_custom_fields thead tr {\n  font-size: 1.1em;\n  font-weight: 700;\n  background: #DDD;\n}\n\n.glz_custom_fields tbody tr.alt {\n  background: #EEE;\n}\n\n.glz_custom_fields td {\n  padding: 2px 10px;\n  vertical-align: middle;\n}\n.glz_custom_fields thead td {\n  padding: 2px 8px 3px 8px;\n}\n.glz_custom_fields td.custom_set_position {\n  text-align: right;\n  width: 10%;\n}\n.glz_custom_fields td.custom_set_name {\n  width: 30%;\n}\n.glz_custom_fields td.type {\n  width: 30%;\n}\n.glz_custom_fields td.events {\n  width: 30%;\n  text-align: right;\n}\n\n.glz_custom_fields_prefs {\n  width: 500px;\n}\n.glz_custom_fields_prefs#list tr th {\n  font-weight: normal;\n  text-align: right;\n  vertical-align: top;\n  width: 50%;\n}\n.glz_custom_fields_prefs#list tr.heading td {\n  padding-top: 30px;\n}\n.glz_custom_fields_prefs#list tr.heading td h2 {\n  margin-top: 0\n}\n.glz_custom_fields_prefs tr td select,\n.glz_custom_fields_prefs tr td input {\n  width: 100%;\n}\n.glz_custom_fields_prefs tr td input.publish {\n  margin-left: 51%;\n  width: auto;\n}\n\n\n\n/* FORMS\n-------------------------------------------------------------- */\n.glz_custom_fields td.events form {\n  display: inline;\n}\n\n#add_edit_custom_field {\n  width: 600px;\n  margin: 2em auto 0 auto;\n}\n#add_edit_custom_field fieldset {\n  padding: 10px;\n}\n#add_edit_custom_field legend {\n  font-size: 1.1em;\n  font-weight: 700;\n}\n#add_edit_custom_field label {\n  width: 20%;\n  font-weight: 700;\n}\n#add_edit_custom_field p input,\n#add_edit_custom_field p select {\n  width: 50%;\n}\n#add_edit_custom_field p textarea {\n  font-size: 0.9em;\n  padding: 1px 0 1px 3px;\n  width: 50%; height: 100px;\n}\n#add_edit_custom_field p span {\n  padding-top: 3px;\n  width: 27%;\n}\n#add_edit_custom_field p em,\n.glz_custom_fields_prefs tr em {\n  font-size: 0.9em;\n  font-weight: 500;\n}\n#add_edit_custom_field input.publish {\n  margin-left: 117px;\n}\n\n/* select on write tab for the custom fields */\ntd#article-col-1 #advanced p select.list {\n  width: 100%;\n}\n\ntd#article-col-1 #advanced p input.radio,\ntd#article-col-1 #advanced p input.checkbox {\n  width: auto;\n}\n</style>\nEOF;\n  // and here come our javascriptz\n  $js = \'\';\n  $date_picker_js = \'\';\n  if ( $date_picker ) {\n    $css .= \'<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"\'.$prefs[\'datepicker_url\'].\'datePicker.css\" />\'.n;\n    foreach (array(\'date.js\', \'datePicker.js\') as $file) {\n      $js .= \'<script type=\"text/javascript\" src=\"\'.$prefs[\'datepicker_url\'].$file.\'\"></script>\'.n;\n    }\n    $date_picker_js = <<<EOF\ntry {\n  Date.firstDayOfWeek = {$prefs[\'datepicker_first_day\']};\n  Date.format = \'{$prefs[\'datepicker_format\']}\';\n  Date.fullYearStart = \'19\';\n  $(\".date-picker\").datePicker({startDate:\'{$prefs[\'datepicker_start_date\']}\'});\n} catch(err) {\n  $(\'#messagepane\').html(\'<a href=\"http://{$prefs[\'siteurl\']}/textpattern/?event=plugin_prefs.glz_custom_fields\">Fix glz_custom_fields configuration</a>\');\n}\nEOF;\n  }\n  $time_picker_js = \'\';\n  if ( $time_picker ) {\n    $css .= \'<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"\'.$prefs[\'timepicker_url\'].\'timePicker.css\" />\'.n;\n    $js .= \'<script type=\"text/javascript\" src=\"\'.$prefs[\'timepicker_url\'].\'timePicker.js\"></script>\'.n;\n    $time_picker_js = <<<EOF\ntry {\n  $(\".time-picker\").timePicker({\n    startTime:\'{$prefs[\'timepicker_start_time\']}\',\n    endTime: \'{$prefs[\'timepicker_end_time\']}\',\n    step: {$prefs[\'timepicker_step\']},\n    show24Hours: {$prefs[\'timepicker_show_24\']}\n  });\n} catch(err) {\n  $(\'#messagepane\').html(\'<a href=\"http://{$prefs[\'siteurl\']}/textpattern/?event=plugin_prefs.glz_custom_fields\">Fix glz_custom_fields configuration</a>\');\n} \nEOF;\n  }\n  $js .= <<<EOF\n<script type=\"text/javascript\">\n<!--//--><![CDATA[//><!--\n\n$(function() {\n  // creating a global object to store variables, functions etc.\n  var GLZ_CUSTOM_FIELDS;\n  if (GLZ_CUSTOM_FIELDS == undefined)\n    GLZ_CUSTOM_FIELDS = {};\n  GLZ_CUSTOM_FIELDS.special_custom_types = [\"date-picker\", \"time-picker\"];\n  GLZ_CUSTOM_FIELDS.no_value_custom_types = [\"text_input\", \"textarea\"];\n  GLZ_CUSTOM_FIELDS.messages = {\n    \'textarea\' : \"<em>Each value on a separate line</em><br /><em>One {default} value allowed</em>\",\n    \'script\' : \"<em>Full path to your script</em>\"\n  }\n\n  // sweet jQuery table striping\n  $(\".stripeMe tr\").mouseover(function() { $(this).addClass(\"over\"); }).mouseout(function() { $(this).removeClass(\"over\"); });\n  $(\".stripeMe tr:even\").addClass(\"alt\");\n\n  // disable all custom field references in Advanced Prefs\n  // prefs_ui doesn\'t offer support for this, getting the custom fields to display right here is not crucial at this point\n  var custom_field_tr = $(\"tr[id*=prefs-custom_], tr:has(h2:contains(\'Custom Fields\'))\").not(\'.glz_custom_fields_prefs tr:has(h2)\');\n  if ( custom_field_tr ) {\n    $.each (custom_field_tr, function() {\n      $(this).hide();\n    });\n  }\n\n  // toggle custom field value based on its type\n  \n  toggle_type_link();\n  if ( $.inArray($(\"select#custom_set_type :selected\").attr(\"value\"), [].concat(GLZ_CUSTOM_FIELDS.special_custom_types, GLZ_CUSTOM_FIELDS.no_value_custom_types)) != -1 ) {\n    custom_field_value_off();\n  }\n  else if ( $(\"select#custom_set_type :selected\").attr(\"value\") == \"custom-script\" )\n    custom_field_value_path();\n\n  $(\"select#custom_set_type\").change( function() {\n    toggle_type_link();\n    if ( $.inArray($(\"select#custom_set_type :selected\").attr(\"value\"), [].concat(GLZ_CUSTOM_FIELDS.special_custom_types, GLZ_CUSTOM_FIELDS.no_value_custom_types)) != -1 ) {\n      custom_field_value_off();\n    }\n    else if ( $(\"select#custom_set_type :selected\").attr(\"value\") == \"custom-script\" )\n      custom_field_value_path();\n    else {\n      custom_field_value_on();\n    }\n  });\n\n  // enable date-picker custom sets\n  {$date_picker_js}\n  \n  // enable time-picker custom sets\n  {$time_picker_js}\n\n  // add a reset link to all radio custom fields\n  if ($(\".glz_custom_radio_field\").length > 0) {\n    $(\".glz_custom_radio_field\").each(function() {\n      custom_field_to_reset = $(this).find(\"input:first\").attr(\"name\");\n      $(this).find(\"label:first\").after(\" <span class=\\\"small\\\">[<a href=\\\"#\\\" class=\\\"glz_custom_field_reset\\\" name=\\\"\" + custom_field_to_reset +\"\\\">Reset</a>]</span>\");\n    });\n\n    // catch the reset action for the above link\n    $(\".glz_custom_field_reset\").click(function() {\n      custom_field_to_reset = $(this).attr(\"name\");\n      // reset our radio input\n      $(\"input[name=\" + custom_field_to_reset + \"]\").attr(\"checked\", false);\n      // add an empty value with the same ID so that it saves the value as empty in the db\n      $(this).after(\"<input type=\\\"hidden\\\" value=\\\"\\\" name=\\\"\"+ custom_field_to_reset +\"\\\" />\");\n      return false;\n    });\n  }\n\n  // ### RE-USABLE FUNCTIONS ###\n\n  function custom_field_value_off() {\n    if ($(\"textarea#value\").length) {\n      GLZ_CUSTOM_FIELDS.textarea_value = $(\"textarea#value\").html();\n      $(\"textarea#value + span.right\").html(\'\');\n      $(\"textarea#value\").remove();\n    }\n    \n    if (!$(\"input#value\").length)\n      $(\"label[for=value]\").after(\'<input id=\"value\" name=\"value\" class=\"left\" />\');\n    $(\"input#value\").attr(\'value\', \"no value allowed\").attr(\'disabled\', \"disabled\");\n    $(\"input#value + span.right\").html(\'\');\n  }\n\n  function custom_field_value_on() {\n    if ( $(\"input#value\").length )\n      $(\"input#value\").remove();\n    if ( !$(\"textarea#value\").length ) {\n      $(\"label[for=value]\").after(\'<textarea id=\"value\" name=\"value\" class=\"left\"></textarea>\');\n      $(\"textarea#value + span.right\").html(GLZ_CUSTOM_FIELDS.messages[\'textarea\']);\n    }\n    if ( GLZ_CUSTOM_FIELDS.textarea_value )\n      $(\"textarea#value\").html(GLZ_CUSTOM_FIELDS.textarea_value);\n  }\n\n  function custom_field_value_path() {\n    if ($(\"textarea#value\").length) {\n      $(\"textarea#value + span.right\").html(\'\');\n      $(\"textarea#value\").remove();\n    }\n    if (!$(\"input#value\").length)\n      $(\"label[for=value]\").after(\'<input id=\"value\" name=\"value\" class=\"left\" />\');\n    if ( $.inArray($(\"input#value\").attr(\'value\'), [\"\", \"no value allowed\"]) != -1 )\n      $(\"input#value\").attr(\'value\', \"{$prefs[\'custom_scripts_path\']}\")\n    $(\"input#value\").attr(\'disabled\', \"\");\n    $(\"input#value + span.right\").html(GLZ_CUSTOM_FIELDS.messages[\'script\']);\n  }\n\n  function toggle_type_link() {\n    $(\"select#custom_set_type\").parent().find(\'span\').remove();\n    if ( $.inArray($(\"select#custom_set_type :selected\").attr(\"value\"), [].concat(GLZ_CUSTOM_FIELDS.special_custom_types, [\"multi-select\"])) != -1 )\n      $(\"select#custom_set_type\").after(\"<span class=\\\"right\\\"><em><a href=\\\"http://{$prefs[\'siteurl\']}/textpattern?event=plugin_prefs.glz_custom_fields\\\">Configure glz_custom_fields</a></em></span>\");\n  }\n\n});\n\n//--><!]]>\n</script>\nEOF;\n\n  // displays the notices we have gathered throughout the entire plugin\n  if ( count($glz_notice) > 0 ) {\n    // let\'s turn our notices into a string\n    $glz_notice = join(\"<br />\", array_unique($glz_notice));\n\n    $js .= \'<script type=\"text/javascript\">\n    <!--//--><![CDATA[//><!--\n\n    $(document).ready(function() {\n      // add our notices\n      $(\"#messagepane\").html(\\\'\'.$glz_notice.\'\\\');\n    });\n    //--><!]]>\n    </script>\';\n  }\n\n  echo $js.n.t.$css.n.t;\n}\n\n\n// -------------------------------------------------------------\n// we are setting up the pre-requisite values for glz_custom_fields\nfunction before_glz_custom_fields() {\n  // we will be reusing these globals across the whole plugin\n  global $all_custom_sets, $glz_notice, $prefs, $date_picker, $time_picker;\n\n  // glz_notice collects all plugin notices\n  $glz_notice = array();\n\n  // let\'s get all custom field sets from prefs\n  $all_custom_sets = glz_custom_fields_MySQL(\"all\");\n\n  // let\'s see if we have a date-picker custom field (first of the special ones)\n  $date_picker = glz_custom_fields_MySQL(\"custom_set_exists\", \"date-picker\");\n  \n  // let\'s see if we have a time-picker custom field\n  $time_picker = glz_custom_fields_MySQL(\"custom_set_exists\", \"time-picker\");\n}\n\n\n// -------------------------------------------------------------\n// bootstrapping routines, run through plugin_lifecycle\nfunction glz_custom_fields_install() {\n  global $all_custom_sets, $glz_notice, $prefs;\n\n  // if jQuery is not present, trigger error\n  // improvement courtesy of Sam Weiss\n  if ( !@fopen($GLOBALS[\'txpcfg\'][\'txpath\'].\'/jquery.js\', \"r\") ) {\n    trigger_error(glz_custom_fields_gTxt(\'jquery_missing\'));\n    trigger_error(glz_custom_fields_gTxt(\'check_path\'));\n  }\n\n  // default custom fields are set to custom_set\n  // need to change this because it confuses our set_types()\n  safe_query(\"\n    UPDATE\n      `\".PFX.\"txp_prefs`\n    SET\n      `html` = \'text_input\'\n    WHERE\n      `event` = \'custom\'\n    AND\n      `html` = \'custom_set\'\n  \");\n\n  // set plugin preferences\n  $arr_plugin_preferences = array(\n    \'values_ordering\'       => \"custom\",\n    \'multiselect_size\'      => \"5\",\n    \'datepicker_url\'        => hu.\"scripts/glz_custom_fields/jquery.datePicker/\",\n    \'datepicker_format\'     => \"dd/mm/yyyy\",\n    \'datepicker_first_day\'  => 1,\n    \'datepicker_start_date\' => \"01/01/1990\",\n    \'timepicker_url\'        => hu.\"scripts/glz_custom_fields/jquery.timePicker/\",\n    \'timepicker_start_time\' => \"00:00\",\n    \'timepicker_end_time\'   => \"23:30\",\n    \'timepicker_step\'       => 30,\n    \'timepicker_show_24\'    => true,\n    \'custom_scripts_path\'   => $prefs[\'path_to_site\'].\"/scripts/glz_custom_fields/\",\n  );\n  glz_custom_fields_MySQL(\"update_plugin_preferences\", $arr_plugin_preferences);\n\n  // let\'s update plugin preferences, make sure they won\'t appear under Admin > Preferences\n  safe_query(\"\n    UPDATE\n      `\".PFX.\"txp_prefs`\n    SET\n      `type` = \'10\'\n    WHERE\n      `event` = \'glz_custom_f\'\n  \");\n\n  // if we don\'t have a search section, let\'s create it because we\'ll need it when searching by custom fields\n  if( !getRow(\"SELECT name FROM `\".PFX.\"txp_section` WHERE name=\'search\'\") ) {\n    safe_query(\"\n      INSERT INTO\n        `\".PFX.\"txp_section` (`name`, `page`, `css`, `is_default`, `in_rss`, `on_frontpage`, `searchable`, `title`)\n      VALUES\n        (\'search\', \'default\', \'default\', \'0\', \'0\', \'0\', \'0\', \'Search\')\n    \");\n    // add a notice that search section has bee created\n    $glz_notice[] = glz_custom_fields_gTxt(\"search_section_created\");\n  }\n\n  // if we don\'t have the custom_fields table, let\'s create it\n  if ( !getRows(\"SHOW TABLES LIKE \'\".PFX.\"custom_fields\'\") ) {\n   safe_query(\"\n     CREATE TABLE `\".PFX.\"custom_fields` (\n      `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,\n       `name` varchar(255) NOT NULL default \'\',\n       `value` varchar(255) NOT NULL default \'\',\n       PRIMARY KEY (id),\n       INDEX (`name`)\n     ) TYPE=MyISAM\n   \");\n  }\n  else {\n    // if there isn\'t and id column, add it\n    if ( !getRows(\"SHOW COLUMNS FROM \".PFX.\"custom_fields LIKE \'id\'\") ) {\n      safe_query(\"\n        ALTER TABLE `\".PFX.\"custom_fields`\n          ADD `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT KEY\n      \");\n    }\n\n   // if we have definitely migrated using this function, skip everything\n   if ( isset($prefs[\'migrated\']) )\n     return;\n   // abort the migration if there are values in custom_fields table, we don\'t want to overwrite anything\n   else if ( glz_custom_fields_MySQL(\'check_migration\') > 0 ) {\n     // DEBUG\n     // dmp(glz_custom_fields_MySQL(\'check_migration\'));\n     $glz_notice[] = glz_custom_fields_gTxt(\"migration_skip\");\n     // make a note of this migration in txp_prefs\n     glz_custom_fields_MySQL(\'mark_migration\');\n     return;\n   }\n\n   // go through all values in custom field columns in textpattern table one by one\n   foreach ($all_custom_sets as $custom => $custom_set) {\n     // check only for custom fields that have been set\n     if ( $custom_set[\'name\'] ) {\n       // get all existing custom values for ALL articles\n       $all_values = glz_custom_fields_MySQL(\'all_values\', glz_custom_number($custom), \'\', array(\'custom_set_name\' => $custom_set[\'name\'], \'status\' => 0));\n       // if we have results, let\'s create SQL queries that will add them to custom_fields table\n       if ( count($all_values) > 0 ) {\n         // initialize insert\n         $insert = \'\';\n         foreach ( $all_values as $escaped_value => $value ) {\n           // don\'t insert empty values or values that are over 255 characters\n           // values over 255 characters hint to a textarea custom field\n           if ( !empty($escaped_value) && strlen($escaped_value) < 255 )\n             // if this is the last value, query will have to be different\n             $insert .= ( end($all_values) != $value ) ?\n               \"(\'{$custom}\',\'{$escaped_value}\'),\" :\n               \"(\'{$custom}\',\'{$escaped_value}\')\";\n         }\n         $query = \"\n           INSERT INTO\n             `\".PFX.\"custom_fields` (`name`,`value`)\n           VALUES\n             {$insert}\n         \";\n         if ( isset($query) && !empty($query) ) {\n           // create all custom field values in custom_fields table\n           safe_query($query);\n           // update the type of this custom field to select (might want to make this user-adjustable at some point)\n           glz_custom_fields_MySQL(\"update\", $custom, PFX.\"txp_prefs\", array(\n             \'custom_set_name\'   => $custom_set[\'name\'],\n             \'custom_set_type\'   => \"select\",\n             \'custom_set_position\' => $custom_set[\'position\']\n           ));\n           $glz_notice[] = glz_custom_fields_gTxt(\"migration_success\");\n         }\n       }\n     }\n   }\n\n   // make a note of this migration in txp_prefs\n   glz_custom_fields_MySQL(\'mark_migration\');\n  }\n}\n\n\n\n\n\n// globals, expensive operations mostly\nbefore_glz_custom_fields();\n\nif (@txpinterface == \"admin\") {\n\n  // INSTALL ROUTINES\n  // checks if all tables exist and everything is setup properly\n  add_privs(\'glz_custom_fields_install\', \"1\");\n  register_callback(\"glz_custom_fields_install\", \"plugin_lifecycle.glz_custom_fields\", \"installed\");\n\n  // we\'ll be doing this only on the pages that we care about, not everywhere\n  if ( in_array(gps(\'event\'), array(\"article\", \"prefs\", \"glz_custom_fields\", \"plugin_prefs.glz_custom_fields\")) ) {\n    // we need some stylesheets & JS\n    add_privs(\'glz_custom_fields_css_js\', \"1,2,3,4,5,6\");\n    register_callback(\'glz_custom_fields_css_js\', \"admin_side\", \'head_end\');\n\n    // we need to make sure that all custom field values will be converted to strings first - think checkboxes & multi-selects etc.\n    if ( (gps(\"step\") == \"edit\") || (gps(\"step\") == \"create\") ) {\n      add_privs(\'glz_custom_fields_before_save\', \"1,2,3,4,5,6\");\n      register_callback(\'glz_custom_fields_before_save\', \"article\", \'\', 1);\n    }\n  }\n\n  // Custom Fields tab under Extensions\n  add_privs(\'glz_custom_fields\', \"1,2\");\n  register_tab(\"extensions\", \'glz_custom_fields\', \"Custom Fields\");\n  register_callback(\'glz_custom_fields\', \"glz_custom_fields\");\n\n  // plugin preferences\n  add_privs(\'plugin_prefs.glz_custom_fields\', \"1,2\");\n  register_callback(\'glz_custom_fields_preferences\', \'plugin_prefs.glz_custom_fields\');\n\n\n  // YES, finally the default custom fields are replaced by the new, pimped ones : )\n  add_privs(\'glz_custom_fields_replace\', \"1,2,3,4,5,6\");\n  register_callback(\'glz_custom_fields_replace\', \'article_ui\', \'custom_fields\');\n  // YES, now we have textarea custom fields as well ; )\n  add_privs(\'glz_custom_fields_replace\', \"1,2,3,4,5,6\");\n  register_callback(\'glz_custom_fields_replace\', \'article_ui\', \'excerpt\');\n}\n\n// -------------------------------------------------------------\n// everything is happening in this function... generates the content for Extensions > Custom Fields\nfunction glz_custom_fields() {\n  global $event, $all_custom_sets, $glz_notice, $prefs;\n\n  // we have $_POST, let\'s see if there is any CRUD\n  if ( $_POST ) {\n    $incoming = stripPost();\n    // DEBUG\n    // die(dmp($incoming));\n    extract($incoming);\n\n    // create an empty $value if it\'s not set in the $_POST\n    if ( !isset($value) )\n      $value = \'\';\n\n    // we are deleting a new custom field\n    if ( gps(\'delete\') ) {\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"txp_prefs\");\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"txp_lang\");\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"custom_fields\");\n\n      glz_custom_fields_MySQL(\"delete\", glz_custom_number($custom_set), PFX.\"textpattern\");\n\n      $glz_notice[] = glz_custom_fields_gTxt(\"deleted\", array(\'{custom_set_name}\' => $custom_set_name));\n    }\n\n    // we are resetting one of the mighty 10\n    if ( gps(\'reset\') ) {\n      glz_custom_fields_MySQL(\"reset\", $custom_set, PFX.\"txp_prefs\");\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"custom_fields\");\n\n      glz_custom_fields_MySQL(\"reset\", glz_custom_number($custom_set), PFX.\"textpattern\", array(\n        \'custom_set_type\' => $custom_set_type,\n        \'custom_field\' => glz_custom_number($custom_set)\n      ));\n\n      $glz_notice[] = glz_custom_fields_gTxt(\"reset\", array(\'{custom_set_name}\' => $custom_set_name));\n    }\n\n    // we are adding a new custom field\n    if ( gps(\"custom_field_number\") ) {\n      $custom_set_name = gps(\"custom_set_name\");\n\n      // if no name was specified, abort\n      if ( !$custom_set_name )\n        $glz_notice[] = glz_custom_fields_gTxt(\"no_name\");\n      else {\n        $custom_set_name = glz_clean_string($custom_set_name);\n\n        $name_exists = glz_check_custom_set_name($all_custom_sets, $custom_set_name);\n\n        // if name doesn\'t exist\n        if ( $name_exists == FALSE ) {\n          glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"txp_prefs\", array(\n            \'custom_field_number\' => $custom_field_number,\n            \'custom_set_type\'     => $custom_set_type,\n            \'custom_set_position\' => $custom_set_position\n          ));\n          glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"txp_lang\", array(\n            \'custom_field_number\' => $custom_field_number,\n            \'lang\'                => $GLOBALS[\'prefs\'][\'language\']\n          ));\n          glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"textpattern\", array(\n            \'custom_field_number\' => $custom_field_number,\n            \'custom_set_type\' => $custom_set_type\n          ));\n          // there are custom fields for which we do not need to touch custom_fields table\n          if ( !in_array($custom_set_type, array(\"textarea\", \"text_input\")) ) {\n            glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"custom_fields\", array(\n              \'custom_field_number\' => $custom_field_number,\n              \'value\'               => $value\n            ));\n          }\n\n          $glz_notice[] = glz_custom_fields_gTxt(\"created\", array(\'{custom_set_name}\' => $custom_set_name));\n        }\n        // name exists, abort\n        else\n          $glz_notice[] = glz_custom_fields_gTxt(\"exists\", array(\'{custom_set_name}\' => $custom_set_name));\n      }\n    }\n\n    // we are editing an existing custom field\n    if ( gps(\'save\') ) {\n      if ( !empty($custom_set_name) ) {\n        $custom_set_name = glz_clean_string($custom_set_name);\n        $name_exists = glz_check_custom_set_name($all_custom_sets, $custom_set_name, $custom_set);\n        // if name doesn\'t exist we\'ll need to create a new custom_set\n        if ( $name_exists == FALSE ) {\n          glz_custom_fields_MySQL(\"update\", $custom_set, PFX.\"txp_prefs\", array(\n            \'custom_set_name\'     => $custom_set_name,\n            \'custom_set_type\'     => $custom_set_type,\n            \'custom_set_position\' => $custom_set_position\n          ));\n\n          // custom sets need to be changed based on their type\n          glz_custom_fields_MySQL(\"update\", $custom_set, PFX.\"textpattern\", array(\n            \'custom_set_type\' => $custom_set_type,\n            \'custom_field\' => glz_custom_number($custom_set)\n          ));\n\n          // for textareas we do not need to touch custom_fields table\n          if ( $custom_set_type != \"textarea\" ) {\n            glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"custom_fields\");\n            glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"custom_fields\", array(\n              \'custom_set\'  => $custom_set,\n              \'value\'       => $value\n            ));\n          }\n\n          $glz_notice[] = glz_custom_fields_gTxt(\"updated\", array(\'{custom_set_name}\' => $custom_set_name));\n        }\n        // name exists, abort\n        else\n          $glz_notice[] = glz_custom_fields_gTxt(\"exists\", array(\'{custom_set_name}\' => $custom_set_name));\n      }\n      else\n        $glz_notice[] = glz_custom_fields_gTxt(\'no_name\');\n    }\n\n    // need to re-fetch data since things modified\n    $all_custom_sets = glz_custom_fields_MySQL(\"all\");\n\n  }\n\n  pagetop(\"Custom Fields\");\n\n  // the table with all custom fields follows\n  echo\n    n.\'<table cellspacing=\"0\" class=\"glz_custom_fields stripeMe\">\'.n.\n    \' <thead>\'.n.\n    \'   <tr>\'.n.\n    \'     <td>Position</td>\'.n.\n    \'     <td>Name</td>\'.n.\n    \'     <td>Type</td>\'.n.\n    \'     <td>&nbsp;</td>\'.n.\n    \'   </tr>\'.n.\n    \' </thead>\'.n.\n    \' <tbody>\'.n;\n\n  // looping through all our custom fields to build the table\n  $i = 0;\n  foreach ( $all_custom_sets as $custom => $custom_set ) {\n    // first 10 fields cannot be deleted, just reset\n    if ( $i < 10 ) {\n      // can\'t reset a custom field that is not set\n      $reset_delete = ( $custom_set[\'name\'] ) ?\n        glz_form_buttons(\"reset\", \"Reset\", $custom, htmlspecialchars($custom_set[\'name\']), $custom_set[\'type\'], \'\', \'return confirm(\\\'By proceeding you will RESET ALL data in `textpattern` and `custom_fields` tables for `\'.$custom.\'`. Are you sure?\\\');\') :\n        NULL;\n    }\n    else {\n      $reset_delete = glz_form_buttons(\"delete\", \"Delete\", $custom, htmlspecialchars($custom_set[\'name\']), $custom_set[\'type\'], \'\', \'return confirm(\\\'By proceeding you will DELETE ALL data in `textpattern` and `custom_fields` tables for `\'.$custom.\'`. Are you sure?\\\');\');\n    }\n\n    $edit = glz_form_buttons(\"edit\", \"Edit\", $custom, htmlspecialchars($custom_set[\'name\']), $custom_set[\'type\'], $custom_set[\'position\']);\n\n    echo\n    \'   <tr>\'.n.\n    \'     <td class=\"custom_set_position\">\'.$custom_set[\'position\'].\'</td>\'.n.\n    \'     <td class=\"custom_set_name\">\'.$custom_set[\'name\'].\'</td>\'.n.\n    \'     <td class=\"type\">\'.(($custom_set[\'name\']) ? glz_custom_fields_gTxt($custom_set[\'type\']) : \'\').\'</td>\'.n.\n    \'     <td class=\"events\">\'.$reset_delete.sp.$edit.\'</td>\'.n.\n    \'   </tr>\'.n;\n\n    $i++;\n  }\n\n  echo\n    \' </tbody>\'.n.\n    \'</table>\'.n;\n\n  // the form where custom fields are being added/edited\n  $legend = gps(\'edit\') ?\n    \'Edit \'.gps(\'custom_set\') :\n    \'Add new custom field\';\n\n  $custom_field = gps(\'edit\') ?\n    \'<input name=\"custom_set\" value=\"\'.gps(\'custom_set\').\'\" type=\"hidden\" />\' :\n    \'<input name=\"custom_field_number\" value=\"\'.glz_custom_next($all_custom_sets).\'\" type=\"hidden\" />\';\n\n  $custom_set = gps(\'edit\') ?\n    gps(\'custom_set\') :\n    NULL;\n\n  $custom_name = gps(\'edit\') ?\n    gps(\'custom_set_name\') :\n    NULL;\n\n  $custom_set_position = gps(\'edit\') ?\n    gps(\'custom_set_position\') :\n    NULL;\n\n  $arr_custom_set_types = glz_custom_set_types();\n\n  $custom_set_types = NULL;\n  foreach ( $arr_custom_set_types as $custom_type_group => $custom_types ) {\n    $custom_set_types .= \'<optgroup label=\"\'.ucfirst($custom_type_group).\'\">\'.n;\n    foreach ($custom_types as $custom_type) {\n      $selected = ( gps(\'edit\') && gps(\'custom_set_type\') == $custom_type ) ?\n        \' selected=\"selected\"\' :\n        NULL;\n      $custom_set_types .= \'<option value=\"\'.$custom_type.\'\"\'.$selected.\'>\'.glz_custom_fields_gTxt($custom_type).\'</option>\'.n;\n    }\n    $custom_set_types .= \'</optgroup>\'.n;\n  }\n  // fetching the values for this custom field\n  if ( gps(\'edit\') ) {\n    if ( $custom_set_type == \"text_input\" )\n      $arr_values = glz_custom_fields_MySQL(\'all_values\', glz_custom_number($custom_set), \'\', array(\'custom_set_name\' => $custom_set_name, \'status\' => 4));\n    else\n      $arr_values = glz_custom_fields_MySQL(\"values\", $custom_set, \'\', array(\'custom_set_name\' => $custom_set_name));\n    \n    $values = ( $arr_values ) ?\n      implode(\"\\r\\n\", $arr_values) :\n      \'\';\n  }\n  else\n    $values = \'\';\n  \n  $action = gps(\'edit\') ?\n    \'<input name=\"save\" value=\"Save\" type=\"submit\" class=\"publish\" />\' :\n    \'<input name=\"add_new\" value=\"Add new\" type=\"submit\" class=\"publish\" />\';\n  // this needs to be different for a script\n  $value = ( isset($custom_set_type) && $custom_set_type == \"custom-script\" ) ?\n    \'<input name=\"value\" id=\"value\" value=\"\'.$values.\'\" class=\"left\"/><span class=\"right\"><em>Full path to your script</em></span>\' :\n    \'<textarea name=\"value\" id=\"value\" class=\"left\">\'.$values.\'</textarea><span class=\"right\"><em>Each value on a separate line</em> <br /><em>One {default} value allowed</em></span>\';\n  \n  // ok, all is set, let\'s build the form\n  echo\n    \'<form method=\"post\" action=\"index.php\" id=\"add_edit_custom_field\">\'.n.\n    \'<input name=\"event\" value=\"glz_custom_fields\" type=\"hidden\" />\'.n.\n    $custom_field.n.\n    \'<fieldset>\'.n.\n    \' <legend>\'.$legend.\'</legend>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"custom_set_name\" class=\"left\">Name:</label>\n        <input name=\"custom_set_name\" value=\"\'.htmlspecialchars($custom_name).\'\" id=\"custom_set_name\" class=\"left\" />\n        <span class=\"right\"><em>Only word characters allowed</em></span>\n      </p>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"custom_set_type\" class=\"left\">Type:</label>\n        <select name=\"custom_set_type\" id=\"custom_set_type\" class=\"left\">\n    \'.      $custom_set_types.\'\n        </select>\n      </p>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"custom_set_position\" class=\"left\">Position:</label>\n        <input name=\"custom_set_position\" value=\"\'.htmlspecialchars($custom_set_position).\'\" id=\"custom_set_position\" class=\"left\" />\n        <span class=\"right\"><em>Automatically assigned if blank</em></span>\n      </p>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"value\" class=\"left\">Value:</label>\n    \'.  $value.\'\n      </p>\'.n.\n    \' \'.$action.n.\n    \'</fieldset>\'.n.\n    \'</form>\'.n;\n}\n\n\n// -------------------------------------------------------------\n// glz_custom_fields preferences\nfunction glz_custom_fields_preferences() {\n  global $event, $glz_notice;\n\n  if ( $_POST && gps(\'save\') ) {\n    glz_custom_fields_MySQL(\"update_plugin_preferences\", $_POST[\'glz_custom_fields_prefs\']);\n    $glz_notice[] = glz_custom_fields_gTxt(\"preferences_updated\");\n    // need to re-fetch from db because this has changed since $prefs has been populated\n  }\n  $current_preferences = glz_custom_fields_MySQL(\'plugin_preferences\');\n\n  pagetop(\"glz_custom_fields Preferences\");\n\n  // custom_fields\n  $arr_values_ordering = array(\n    \'ascending\'   => \"Ascending\",\n    \'descending\'  => \"Descending\",\n    \'custom\'      => \"As entered\"\n  );\n  $values_ordering = \'<select name=\"glz_custom_fields_prefs[values_ordering]\" id=\"glz_custom_fields_prefs_values_ordering\">\';\n  foreach ( $arr_values_ordering as $value => $title ) {\n    $selected = ($current_preferences[\'values_ordering\'] == $value) ? \' selected=\"selected\"\' : \'\';\n    $values_ordering .= \"<option value=\\\"$value\\\"$selected>$title</option>\";\n  }\n  $values_ordering .= \"</select>\";\n  $multiselect_size = \'<input type=\"text\" name=\"glz_custom_fields_prefs[multiselect_size]\" id=\"glz_custom_fields_prefs_multiselect_size\" value=\"\'.$current_preferences[\'multiselect_size\'].\'\" />\';\n  $custom_scripts_path_error = ( @fopen($current_preferences[\'custom_scripts_path\'], \"r\") ) ?\n    \'\' :\n    \'<br /><em class=\"red\">Folder does not exist, please create it.</em>\';\n\n  // jquery.datePicker\n  $datepicker_url_error = ( @fopen($current_preferences[\'datepicker_url\'].\"datePicker.js\", \"r\") ) ?\n    \'\' :\n    \'<br /><em class=\"red\">Folder does not exist, please create it.</em>\';\n  $arr_date_format = array(\"dd/mm/yyyy\", \"mm/dd/yyyy\", \"yyyy-mm-dd\", \"dd mm yy\");\n  $date_format = \'<select name=\"glz_custom_fields_prefs[datepicker_format]\" id=\"glz_custom_fields_prefs_datepicker_format\">\';\n  foreach ( $arr_date_format as $format ) {\n    $selected = ($current_preferences[\'datepicker_format\'] == $format) ? \' selected=\"selected\"\' : \'\';\n    $date_format .= \"<option value=\\\"$format\\\"$selected>$format</option>\";\n  }\n  $date_format .= \"</select>\";\n\n  $arr_days = array(\'Sunday\', \'Monday\', \'Tuesday\', \'Wednesday\', \'Thursday\', \'Friday\', \'Saturday\');\n  $first_day = \'<select name=\"glz_custom_fields_prefs[datepicker_first_day]\" id=\"glz_custom_fields_prefs_datepicker_first_day\">\';\n  foreach ( $arr_days as $key => $day ) {\n    $selected = ($current_preferences[\'datepicker_first_day\'] == $key) ? \' selected=\"selected\"\' : \'\';\n    $first_day .= \"<option value=\\\"$key\\\"$selected>$day</option>\";\n  }\n  $first_day .= \"</select>\";\n\n  $start_date = \'<input type=\"text\" name=\"glz_custom_fields_prefs[datepicker_start_date]\" id=\"glz_custom_fields_prefs_datepicker_start_date\" value=\"\'.$current_preferences[\'datepicker_start_date\'].\'\" />\';\n  \n  // jquery.timePicker\n  $timepicker_url_error = ( @fopen($current_preferences[\'timepicker_url\'].\"timePicker.js\", \"r\") ) ?\n    \'\' :\n    \'<br /><em class=\"red\">Folder does not exist, please create it.</em>\';\n  $arr_time_format = array(\'true\' => \"24 hours\", \'false\' => \"12 hours\");\n  $show_24 = \'<select name=\"glz_custom_fields_prefs[timepicker_show_24]\" id=\"glz_custom_fields_prefs_timepicker_show_24\">\';\n  foreach ( $arr_time_format as $value => $title ) {\n    $selected = ($current_preferences[\'timepicker_show_24\'] == $value) ? \' selected=\"selected\"\' : \'\';\n    $show_24 .= \"<option value=\\\"$value\\\"$selected>$title</option>\";\n  }\n  $show_24 .= \"</select>\";\n\n  $out = <<<EOF\n<form action=\"index.php\" method=\"post\">\n<table id=\"list\" class=\"glz_custom_fields_prefs\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">\n  <tbody>\n    <tr class=\"heading\">\n      <td colspan=\"2\"><h2 class=\"pref-heading\">Custom Fields</h2></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_values_ordering\">Order for custom field values</th>\n      <td>{$values_ordering}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_multiselect_size\">Multi-select field size</th>\n      <td>{$multiselect_size}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_custom_scripts_path\">Custom scripts path</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[custom_scripts_path]\" id=\"glz_custom_fields_prefs_custom_scripts_path\" value=\"{$current_preferences[\'custom_scripts_path\']}\" />{$custom_scripts_path_error}</td>\n    </tr>\n    \n    <tr class=\"heading\">\n      <td colspan=\"2\"><h2 class=\"pref-heading left\">Date Picker</h2> <a href=\"http://www.kelvinluck.com/assets/jquery/datePicker/v2/demo/index.html\" title=\"A flexible unobtrusive calendar component for jQuery\" class=\"right\">jQuery datePicker</a></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_url\">Date Picker plugin URL</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[datepicker_url]\" id=\"glz_custom_fields_prefs_datepicker_url\" value=\"{$current_preferences[\'datepicker_url\']}\" />{$datepicker_url_error}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_format\">Date format</th>\n      <td>{$date_format}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_first_day\">First day of week</th>\n      <td>{$first_day}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_start_date\">Start date</th>\n      <td>{$start_date}<br /><em class=\"grey\">MUST be the same as \"Date format\"</em></td>\n    </tr>\n    \n    <tr class=\"heading\">\n      <td colspan=\"2\"><h2 class=\"pref-heading left\">Time Picker</h2> <a href=\"http://labs.perifer.se/timedatepicker/\" title=\"jQuery time picker\" class=\"right\">jQuery timePicker</a></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_url\">Time Picker plugin URL</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_url]\" id=\"glz_custom_fields_prefs_timepicker_url\" value=\"{$current_preferences[\'timepicker_url\']}\" />{$timepicker_url_error}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_start_time\">Start time</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_start_time]\" id=\"glz_custom_fields_prefs_timepicker_start_time\" value=\"{$current_preferences[\'timepicker_start_time\']}\" /></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_end_time\">End time</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_end_time]\" id=\"glz_custom_fields_prefs_timepicker_end_time\" value=\"{$current_preferences[\'timepicker_end_time\']}\" /></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_step\">Step</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_step]\" id=\"glz_custom_fields_prefs_timepicker_step\" value=\"{$current_preferences[\'timepicker_step\']}\" /></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_step\">Time format</th>\n      <td>{$show_24}</td>\n    </tr>\n    \n    <tr>\n      <td colspan=\"2\" class=\"noline\">\n        <input class=\"publish\" type=\"submit\" name=\"save\" value=\"Save\" />\n        <input type=\"hidden\" name=\"event\" value=\"plugin_prefs.glz_custom_fields\" />\n      </td>\n    </tr>\n  </tbody>\n</table>\nEOF;\n\n  echo $out;\n}','# glz_custom_fields v1.2.4\n# Unlimited, super special custom fields.\n#\n# Gerhard Lazu\n# http://gerhardlazu.com\n#\n# Contributors: Randy Levine, Sam Weiss, Luca Botti, Manfre, Vladimir Siljkovic, Julian Reisenberger, Steve Dickinson, Stef Dawson, Jean-Pol Dupont\n# Minimum requirements: Textpattern 4.2.0\n\n// Including helper files. If we can\'t have classes, we will use includes\n\n\n// -------------------------------------------------------------\n// messages that will be available throughout this plugin\nfunction glz_custom_fields_gTxt($get, $atts = array()) {\n  $lang = array(\n    \'no_name\'           => \'Ooops! <strong>custom set</strong> must have a name\',\n    \'deleted\'           => \'<strong>{custom_set_name}</strong> was deleted\',\n    \'reset\'             => \'<strong>{custom_set_name}</strong> was reset\',\n    \'created\'           => \'<strong>{custom_set_name}</strong> was created\',\n    \'updated\'           => \'<strong>{custom_set_name}</strong> was updated\',\n    \'exists\'            => \'Ooops! <strong>{custom_set_name}</strong> already exists\',\n    \'doesnt_exist\'      => \'Ooops! <strong>{custom_set_name}</strong> is not set\',\n    \'field_problems\'    => \'Ooops! <strong>{custom_set_name}</strong> has some problems. <a href=\"?event=glz_custom_fields\">Go fix it</a>.\',\n    \'custom_set\'        => \'Text Input\', # custom sets in TXP 4.2.0 are by type custom_set by default...\n    \'text_input\'        => \'Text Input\',\n    \'select\'            => \'Select\',\n    \'multi-select\'      => \'Multi-Select\',\n    \'textarea\'          => \'Textarea\',\n    \'checkbox\'          => \'Checkbox\',\n    \'radio\'             => \'Radio\',\n    \'date-picker\'       => \'Date Picker\',\n    \'time-picker\'       => \'Time Picker\',\n    \'custom-script\'     => \'Custom Script\',\n    \'type_not_supported\'=> \'Type not supported\',\n    \'no_do\'             => \'Ooops! No action specified for method, abort.\',\n    \'not_specified\'     => \'Ooops! {what} is not specified\',\n    \'searchby_not_set\'  => \'<strong>searcby</strong> cannot be left blank\',\n    \'jquery_missing\'    => \'Upgrade TXP to at least 4.0.5 or put <strong>jquery.js</strong> in your /textpattern folder. <a href=\"http://jquery.com\" title=\"jQuery website\">jQuery website</a>\',\n    \'check_path\'        => \'Make sure all your paths are correct. Check <strong>config.php</strong> and the Admin tab (mainly Advanced).\',\n    \'no_articles_found\' => \'No articles with custom fields have been found.\',\n    \'migration_success\' => \'Migrating custom fields was successful\',\n    \'migration_skip\'    => \'<strong>custom_fields</strong> table already has data in it, migration skipped.\',\n    \'search_section_created\'  => \'<strong>search</strong> section has been created\',\n    \'custom_sets_all_input\'   => \'All custom sets have been set back to input\',\n    \'preferences_updated\'     => \'Plugin preferences have been updated\',\n    \'not_found\'         => \'Ooops! <strong>{file}</strong> cannot be found, check path\',\n    \'not_callable\'      => \'Ooops! <strong>{function}()</strong> cannot be called. Ensure <strong>{file}</strong> can be executed.\'\n  );\n\n  $out = ( strstr($lang[$get], \"Ooops!\") ) ? // Ooops! would appear 0 in the string...\n      \"<span class=\\\"red\\\">{$lang[$get]}</span>\" :\n      $lang[$get];\n\n  return strtr($out, $atts);\n}\n\n\n\n\n\n\n// -------------------------------------------------------------\n// I would do this through a factory class, but some folks are still running PHP4...\nfunction glz_custom_fields_MySQL($do, $name=\'\', $table=\'\', $extra=\'\') {\n  if ( !empty($do) ) {\n    switch ( $do ) {\n      case \'all\':\n        return glz_all_custom_sets();\n        break;\n\n      case \'values\':\n        return glz_values_custom_field($name, $extra);\n        break;\n\n      case \'all_values\' :\n        return glz_all_existing_custom_values($name, $extra);\n        break;\n\n      case \'article_customs\':\n        return glz_article_custom_fields($name, $extra);\n        break;\n\n      case \'next_custom\':\n        return glz_next_empty_custom();\n        break;\n\n      case \'new\':\n        glz_new_custom_field($name, $table, $extra);\n        glz_custom_fields_update_count();\n        break;\n\n      case \'update\':\n        return glz_update_custom_field($name, $table, $extra);\n        break;\n\n      case \'reset\':\n        return glz_reset_custom_field($name, $table, $extra);\n        break;\n\n      case \'delete\':\n        glz_delete_custom_field($name, $table);\n        glz_custom_fields_update_count();\n        break;\n\n      case \'check_migration\':\n        return glz_check_migration();\n        break;\n\n      case \'mark_migration\':\n        return glz_mark_migration();\n        break;\n\n      case \'custom_set_exists\':\n        return glz_check_custom_set_exists($name);\n        break;\n\n      case \'plugin_preferences\':\n        return glz_plugin_preferences($name);\n        break;\n\n      case \'update_plugin_preferences\':\n        return glz_update_plugin_preferences($name);\n        break;\n    }\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'no_do\'));\n}\n\n\nfunction glz_all_custom_sets() {\n  $all_custom_sets = getRows(\"\n    SELECT\n      `name` AS custom_set,\n      `val` AS name,\n      `position`,\n      `html` AS type\n    FROM\n      `\".PFX.\"txp_prefs`\n    WHERE\n      `event`=\'custom\'\n    ORDER BY\n      `position`\n  \");\n\n  foreach ( $all_custom_sets as $custom_set ) {\n    $out[$custom_set[\'custom_set\']] = array(\n      \'name\'      => $custom_set[\'name\'],\n      \'position\'  => $custom_set[\'position\'],\n      \'type\'      => $custom_set[\'type\']\n    );\n  }\n\n  return $out;\n}\n\n\nfunction glz_values_custom_field($name, $extra) {\n  global $prefs;\n\n  if ( is_array($extra) ) {\n    extract($extra);\n\n    if ( !empty($name) ) {\n      switch ( $prefs[\'values_ordering\'] ) {\n        case \"ascending\":\n          $orderby = \"value ASC\";\n          break;\n        case \"descending\":\n          $orderby = \"value DESC\";\n          break;\n        default:\n          $orderby = \"id ASC\";\n      }\n\n\n      $arr_values = getThings(\"\n        SELECT\n          `value`\n        FROM\n          `\".PFX.\"custom_fields`\n        WHERE\n          `name` = \'{$name}\'\n        ORDER BY\n          {$orderby}\n      \");\n\n      if ( count($arr_values) > 0 ) {\n        // decode all special characters e.g. \", & etc. and use them for keys\n        foreach ( $arr_values as $key => $value )\n          $arr_values_formatted[glz_return_clean_default(htmlspecialchars($value))] = stripslashes($value);\n\n        // if this is a range, format ranges accordingly\n        return glz_format_ranges($arr_values_formatted, $custom_set_name);\n      }\n    }\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_all_existing_custom_values($name, $extra) {\n  if ( is_array($extra) ) {\n    extract(lAtts(array(\n      \'custom_set_name\'   => \"\",\n      \'status\'            => 4\n    ),$extra));\n\n    // we might want to check the custom field values for all articles - think initial migration\n    $status_condition = ($status == 0) ? \"<> \'\'\" : \"= \'$status\'\";\n\n    if ( !empty($name) ) {\n      $arr_values = getThings(\"\n        SELECT DISTINCT\n          `$name`\n        FROM\n          `\".PFX.\"textpattern`\n        WHERE\n          `Status` $status_condition\n        AND\n          `$name` <> \'\'\n        ORDER BY\n          `$name`\n        \");\n\n      // trim all values\n      foreach ( $arr_values as $key => $value )\n        $arr_values[$key] = trim($value);\n\n      // DEBUG\n      // dmp($arr_values);\n\n      // prepare our array for checking. We need a single string to check for | instances - seems quickest.\n      $values_check = join(\'::\', $arr_values);\n\n      // DEBUG\n      // dmp($values_check);\n\n      // check if some of the values are multiple ones\n      if ( strstr($values_check, \'|\') ) {\n        // initialize $out\n        $out = array();\n        // put all values in an array\n        foreach ( $arr_values as $value ) {\n          $arr_values = explode(\'|\', $value);\n          $out = array_merge($out, $arr_values);\n        }\n        // keep only the unique ones\n        $out = array_unique($out);\n        // keys and values need to be the same\n        $out = php4_array_combine($out, $out);\n      }\n\n      // check if this is a range\n      else if ( strstr($values_check, \'-\') && strstr($custom_set_name, \'range\') )\n        // keys won\'t have the unit ($, £, m<sup>3</sup>, etc.) values will\n        $out = glz_format_ranges($arr_values, $custom_set_name);\n      else\n        // keys and values need to be the same\n        $out = php4_array_combine($arr_values, $arr_values);\n\n      // calling stripslashes on all array values\n      array_map(\'glz_array_stripslashes\', $out);\n\n      return $out;\n    }\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_article_custom_fields($name, $extra) {\n  if ( is_array($extra) ) {\n    // see what custom fields we need to query for\n    foreach ( $extra as $custom => $custom_set )\n      $select[] = glz_custom_number($custom);\n\n    // prepare the select elements\n    $select = implode(\',\', $select);\n\n    $arr_article_customs = getRow(\"\n      SELECT\n        $select\n      FROM\n        `\".PFX.\"textpattern`\n      WHERE\n        `ID`=\'$name\'\n    \");\n\n    return $arr_article_customs;\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_new_custom_field($name, $table, $extra) {\n  if ( is_array($extra) ) {\n    extract($extra);\n    // DRYing up, we\'ll be using this variable quiet often\n    $custom_set = ( isset($custom_field_number) ) ?\n      \"custom_{$custom_field_number}_set\" :\n      $custom_set;\n\n    if ( ($table == PFX.\"txp_prefs\") ) {\n      // if this is a new field without a position, use the $custom_field_number\n      if (empty($custom_set_position)) $custom_set_position = $custom_field_number;\n      $query = \"\n        INSERT INTO\n          `\".PFX.\"txp_prefs` (`prefs_id`, `name`, `val`, `type`, `event`, `html`, `position`)\n        VALUES\n          (\'1\', \'{$custom_set}\', \'{$name}\', \'1\', \'custom\', \'{$custom_set_type}\', {$custom_set_position})\n      \";\n    }\n    else if ( $table == PFX.\"txp_lang\" ) {\n      $query = \"\n        INSERT INTO\n          `\".PFX.\"txp_lang` (`id`,`lang`,`name`,`event`,`data`,`lastmod`)\n        VALUES\n          (\'\',\'{$lang}\',\'{$custom_set}\',\'prefs\',\'{$name}\',now())\n      \";\n    }\n    else if ( $table == PFX.\"textpattern\" ) {\n      $column_type = ( $custom_set_type == \"textarea\" ) ? \"TEXT\" : \"VARCHAR(255)\";\n      $query = \"\n        ALTER TABLE\n          `\".PFX.\"textpattern`\n        ADD\n          `custom_{$custom_field_number}` {$column_type} NOT NULL DEFAULT \'\'\n      \";\n    }\n    else if ( $table == PFX.\"custom_fields\" ) {\n      $arr_values = array_unique(array_filter(explode(\"\\r\\n\", $value), \'glz_arr_empty_values\'));\n\n      if ( is_array($arr_values) && !empty($arr_values) ) {\n        $size_arr_values = count($arr_values);\n        $insert = \'\';\n        foreach ( $arr_values as $key => $value ) {\n          // don\'t insert empty values\n          if ( !empty($value) )\n            // make sure special characters are escaped before inserting them in the database\n            $value = addslashes(addslashes(trim($value)));\n            // if this is the last value, query will have to be different\n            $insert .= ($key+1 != $size_arr_values ) ?\n              \"(\'{$custom_set}\',\'{$value}\'), \" :\n              \"(\'{$custom_set}\',\'{$value}\')\";\n        }\n        $query = \"\n          INSERT INTO\n            `\".PFX.\"custom_fields` (`name`,`value`)\n          VALUES\n            {$insert}\n        \";\n      }\n    }\n    if ( isset($query) && !empty($query) )\n      safe_query($query);\n  }\n  else\n    trigger_error(glz_custom_fields_gTxt(\'not_specified\', array(\'{what}\' => \"extra attributes\")));\n}\n\n\nfunction glz_update_custom_field($name, $table, $extra) {\n  if ( is_array($extra) )\n    extract($extra);\n\n  if ( ($table == PFX.\"txp_prefs\") ) {\n    safe_query(\"\n      UPDATE\n        `\".PFX.\"txp_prefs`\n      SET\n        `val` = \'{$custom_set_name}\',\n        `html` = \'{$custom_set_type}\',\n        `position` = \'{$custom_set_position}\'\n      WHERE\n        `name`=\'{$name}\'\n    \");\n  }\n  else if ( ($table == PFX.\"textpattern\") ) {\n    $column_type = ( $custom_set_type == \"textarea\" ) ? \"TEXT\" : \"VARCHAR(255)\";\n    safe_query(\"\n      ALTER TABLE\n        `\".PFX.\"textpattern`\n      MODIFY\n        `{$custom_field}` {$column_type} NOT NULL DEFAULT \'\'\n    \");\n  }\n}\n\n\nfunction glz_reset_custom_field($name, $table, $extra) {\n  if ( is_array($extra) )\n    extract($extra);\n\n  if ( $table == PFX.\"txp_prefs\" ) {\n    safe_query(\"\n      UPDATE\n        `\".PFX.\"txp_prefs`\n      SET\n        `val` = \'\',\n        `html` = \'text_input\'\n      WHERE\n        `name`=\'{$name}\'\n    \");\n  }\n  else if ( $table == PFX.\"textpattern\" ) {\n    safe_query(\"UPDATE `\".PFX.\"textpattern` SET `{$name}` = \'\'\");\n    safe_query(\"ALTER TABLE `\".PFX.\"textpattern` MODIFY `{$custom_field}` VARCHAR(255) NOT NULL DEFAULT \'\'\");\n  }\n}\n\n\nfunction glz_delete_custom_field($name, $table) {\n  // remember, custom fields under 10 MUST NOT be deleted\n  if ( glz_custom_digit($name) > 10 ) {\n    if ( in_array($table, array(PFX.\"txp_prefs\", PFX.\"txp_lang\", PFX.\"custom_fields\")) ) {\n      $query = \"\n        DELETE FROM\n          `{$table}`\n        WHERE\n          `name`=\'{$name}\'\n      \";\n    }\n    else if ( $table == PFX.\"textpattern\" ) {\n      $query = \"\n        ALTER TABLE\n          `\".PFX.\"textpattern`\n        DROP\n          `{$name}`\n      \";\n    }\n    safe_query($query);\n  }\n  else {\n    if ( $table == PFX.\"txp_prefs\" )\n      glz_custom_fields_MySQL(\"reset\", $name, $table);\n    else if ( ($table == PFX.\"custom_fields\") ) {\n      safe_query(\"\n        DELETE FROM\n          `{$table}`\n        WHERE\n          `name`=\'{$name}\'\n      \");\n    }\n  }\n}\n\n\n// -------------------------------------------------------------\n// checks if custom_fields table has any values in it\nfunction glz_check_migration() {\n  return getThing(\"\n    SELECT\n      COUNT(*)\n    FROM\n      `\".PFX.\"custom_fields`\n  \");\n}\n\n\n// -------------------------------------------------------------\n// make a note of glz_custom_fields migration in txp_prefs\nfunction glz_mark_migration() {\n  set_pref(\"migrated\", \"1\", \"glz_custom_f\");\n}\n\n\n// -------------------------------------------------------------\n// check if one of the special custom fields exists\nfunction glz_check_custom_set_exists($name) {\n  if ( !empty($name) ) {\n    return getThing(\"\n      SELECT\n        `name`, `val`\n      FROM\n        `\".PFX.\"txp_prefs`\n      WHERE\n        `html` = \'{$name}\'\n      AND\n        `name` LIKE \'custom_%\'\n      ORDER BY\n        `name`\n    \");\n  }\n}\n\n\n// -------------------------------------------------------------\n// updates max_custom_fields\nfunction glz_custom_fields_update_count() {\n  set_pref(\'max_custom_fields\', safe_count(\"txp_prefs\", \"event=\'custom\'\"));\n}\n\n// -------------------------------------------------------------\n// returns all plugin preferences\nfunction glz_plugin_preferences($arr_preferences) {\n	$r = safe_rows_start(\'name, val\', \'txp_prefs\', \"event = \'glz_custom_f\'\");\n	if ($r) {\n		while ($a = nextRow($r)) {\n			$out[$a[\'name\']] = stripslashes($a[\'val\']);\n		}\n	}\n  return $out;\n}\n\n// -------------------------------------------------------------\n// updates all plugin preferences\nfunction glz_update_plugin_preferences($arr_preferences) {\n  // die(dmp($arr_preferences));\n  foreach ($arr_preferences as $preference => $value) {\n    // if there is a preference which doesn\'t exist, create it\n    if ( !isset($prefs[$preference]) )\n      set_pref($preference, addslashes(addslashes(trim($value))), \"glz_custom_f\", 10); // 10 so that it won\'t appear under TXP\'s prefs tab\n  }\n}\n\n\n\n\n\n\n// this function doesn\'t seem to be currently used, remove or make it useful\nfunction glz_next_empty_custom() {\n  global $all_custom_sets;\n\n  foreach ( $all_custom_sets as $custom => $custom_set ) {\n    if ( empty($custom_set[\'name\']) )\n      return $custom;\n  }\n}\n\n\n// -------------------------------------------------------------\n// edit/delete buttons in custom_fields table require a form each\nfunction glz_form_buttons($action, $value, $custom_set, $custom_set_name, $custom_set_type, $custom_set_position, $onsubmit=\'\') {\n  $onsubmit = ($onsubmit) ?\n    \'onsubmit=\"\'.$onsubmit.\'\"\' :\n    \'\';\n\n  return\n    \'<form method=\"post\" action=\"index.php\" \'.$onsubmit.\'>\n      <input name=\"custom_set\" value=\"\'.$custom_set.\'\" type=\"hidden\" />\n      <input name=\"custom_set_name\" value=\"\'.$custom_set_name.\'\" type=\"hidden\" />\n      <input name=\"custom_set_type\" value=\"\'.$custom_set_type.\'\" type=\"hidden\" />\n      <input name=\"custom_set_position\" value=\"\'.$custom_set_position.\'\" type=\"hidden\" />\n      <input name=\"event\" value=\"glz_custom_fields\" type=\"hidden\" />\n      <input name=\"\'.$action.\'\" value=\"\'.$value.\'\" type=\"submit\" />\n    </form>\';\n}\n\n\n// -------------------------------------------------------------\n// the types our custom fields can take\nfunction glz_custom_set_types() {\n  return array(\n    \'normal\' => array(\n      \'text_input\',\n      \'checkbox\',\n      \'radio\',\n      \'select\',\n      \'multi-select\',\n      \'textarea\'),\n    \'special\' => array(\n      \'date-picker\',\n      \'time-picker\',\n      \'custom-script\')\n  );\n}\n\n\n// -------------------------------------------------------------\n// outputs only custom fields that have been set, i.e. have a name assigned to them\nfunction glz_check_custom_set($all_custom_sets, $step) {\n  $out = array();\n\n  foreach ($all_custom_sets as $key => $custom_field) {\n    if (!empty($custom_field[\'name\'])) {\n      if ( ($step == \"excerpt\") && ($custom_field[\'type\'] == \"textarea\") )\n        $out[$key] = $custom_field;\n      else if ( ($step == \"custom_fields\") && ($custom_field[\'type\'] != \"textarea\") ) {\n        $out[$key] = $custom_field;\n      }\n    }\n  }\n\n  return $out;\n}\n\n\n// -------------------------------------------------------------\n// removes { } from values which are marked as default\nfunction glz_return_clean_default($value) {\n  $pattern = \"/^.*\\{(.*)\\}.*/\";\n\n  return preg_replace($pattern, \"$1\", $value);\n}\n\n\n// -------------------------------------------------------------\n// return our default value from all custom_field values\nfunction glz_default_value($all_values) {\n  if ( is_array($all_values) ) {\n    preg_match(\"/(\\{.*\\})/\", join(\" \", $all_values), $default);\n    return ( (!empty($default) && $default[0]) ? $default[0] : \'\');\n  }\n}\n\n\n// -------------------------------------------------------------\n// calling the above function in an array context\nfunction glz_clean_default_array_values(&$value) {\n  $value = glz_return_clean_default($value);\n}\n\n\n// -------------------------------------------------------------\n// custom_set without \"_set\" e.g. custom_1_set => custom_1\n// or custom set formatted for IDs e.g. custom-1\nfunction glz_custom_number($custom_set, $delimiter=\"_\") {\n  $custom_field = substr($custom_set, 0, -4);\n\n  if ($delimiter != \"_\")\n    $custom_field = str_replace(\"_\", $delimiter, $custom_field);\n\n  return $custom_field;\n}\n\n\n// -------------------------------------------------------------\n// custom_set digit e.g. custom_1_set => 1\nfunction glz_custom_digit($custom_set) {\n  $out = explode(\"_\", $custom_set);\n  // $out[0] will always be custom\n  return $out[1];\n}\n\n\n// -------------------------------------------------------------\n// removes empty values from arrays - used for new custom fields\nfunction glz_arr_empty_values($value) {\n  if ( !empty($value) )\n    return $value;\n}\n\n\n// -------------------------------------------------------------\n// returns the custom set from a custom set name e.g. \"Rating\" gives us custom_1_set\nfunction glz_get_custom_set($value) {\n  global $all_custom_sets;\n\n  // go through all custom fields and see if the one we\'re looking for exists\n  foreach ( $all_custom_sets as $custom => $custom_set ) {\n    if ( $custom_set[\'name\'] == $value )\n      return $custom;\n  }\n  // if it doesn\'t, return error message\n  trigger_error(glz_custom_fields_gTxt(\'doesnt_exist\', array(\'{custom_set_name}\' => $value)));\n}\n\n\n// -------------------------------------------------------------\n// get the article ID, EVEN IF it\'s newly saved\nfunction glz_get_article_id() {\n  return ( !empty($GLOBALS[\'ID\']) ?\n    $GLOBALS[\'ID\'] :\n    gps(\'ID\') );\n}\n\n\n// -------------------------------------------------------------\n// helps with range formatting - just DRY\nfunction glz_format_ranges($arr_values, $custom_set_name) {\n  //initialize $out\n  $out = \'\';\n  foreach ( $arr_values as $key => $value ) {\n    $out[$key] = ( strstr($custom_set_name, \'range\') ) ?\n      glz_custom_fields_range($value, $custom_set_name) :\n      $value;\n  }\n  return $out;\n}\n\n\n// -------------------------------------------------------------\n// acts as a callback for the above function\nfunction glz_custom_fields_range($custom_value, $custom_set_name) {\n  // last part of the string will be the range unit (e.g. $, &pound;, m<sup>3</sup> etc.)\n  $nomenclature = array_pop(explode(\' \', $custom_set_name));\n\n  // see whether range unit should go after\n  if ( strstr($nomenclature, \'(after)\') ) {\n    // trim \'(after)\' from the measuring unit\n    $nomenclature = substr($nomenclature, 0, -7);\n    $after = 1;\n  }\n\n  // check whether it\'s a range or single value\n  $arr_value = explode(\'-\', $custom_value);\n  if ( is_array($arr_value) ) {\n    // initialize $out\n    $out = \'\';\n    foreach ( $arr_value as $value ) {\n      // check whether nomenclature goes before or after\n      $out[] = ( !isset($after) ) ?\n        $nomenclature.number_format($value) :\n        number_format($value).$nomenclature;\n    }\n    return implode(\'-\', $out);\n  }\n  // our range is a single value\n  else {\n    // check whether nomenclature goes before or after\n    return ( !isset($after) ) ?\n      $nomenclature.number_format($value) :\n      number_format($value).$nomenclature;\n  }\n}\n\n\n// -------------------------------------------------------------\n// returns the next available number for custom set\nfunction glz_custom_next($arr_custom_sets) {\n  $arr_extra_custom_sets = array();\n  foreach ( array_keys($arr_custom_sets) as $extra_custom_set) {\n    $arr_extra_custom_sets[] = glz_custom_digit($extra_custom_set);\n  }\n  // order the array\n  sort($arr_extra_custom_sets);\n\n  for ( $i=0; $i < count($arr_extra_custom_sets); $i++ ) {\n    if ($arr_extra_custom_sets[$i] > $i+1)\n      return $i+1;\n  }\n\n  return count($arr_extra_custom_sets)+1;\n}\n\n\n// -------------------------------------------------------------\n// checks if the custom field name isn\'t already taken\nfunction glz_check_custom_set_name($arr_custom_fields, $custom_set_name, $custom_set=\'\') {\n  foreach ( $arr_custom_fields as $custom => $arr_custom_set ) {\n    if ( ($custom_set_name == $arr_custom_set[\'name\']) && (!empty($custom_set) && $custom_set != $custom) )\n      return TRUE;\n  }\n\n  return FALSE;\n}\n\n\n// -------------------------------------------------------------\n// formats the custom set output based on its type\nfunction glz_format_custom_set_by_type($custom, $custom_id, $custom_set_type, $arr_custom_field_values, $custom_value = \"\", $default_value = \"\") {\n  if ( is_array($arr_custom_field_values) )\n    $arr_custom_field_values = array_map(\'glz_array_stripslashes\', $arr_custom_field_values);\n\n  switch ( $custom_set_type ) {\n    // these are the normal custom fields\n    case \"text_input\":\n      return array(\n        fInput(\"text\", $custom, $custom_value, \"edit\", \"\", \"\", \"22\", \"\", $custom_id),\n        \'glz_custom_field\'\n      );\n\n    case \"select\":\n      return array(\n        glz_selectInput($custom, $custom_id, $arr_custom_field_values, $custom_value, $default_value),\n        \'glz_custom_select_field\'\n      );\n\n    case \"multi-select\":\n      return array(\n        glz_selectInput($custom, $custom_id, $arr_custom_field_values, $custom_value, $default_value, 1),\n        \'glz_custom_multi-select_field\'\n      );\n\n    case \"checkbox\":\n      return array(\n        glz_checkbox($custom, $arr_custom_field_values, $custom_value, $default_value),\n        \'glz_custom_checkbox_field\'\n      );\n\n    case \"radio\":\n      return array(\n        glz_radio($custom, $custom_id, $arr_custom_field_values, $custom_value, $default_value),\n        \'glz_custom_radio_field\'\n      );\n\n    case \"textarea\":\n      return array(\n        text_area($custom, 100, 500, $custom_value, $custom_id),\n        \'glz_text_area_field\'\n      );\n\n    // here start the special custom fields, might need to refactor the return, starting to repeat itself\n    case \"date-picker\":\n      return array(\n        fInput(\"text\", $custom, $custom_value, \"edit date-picker\", \"\", \"\", \"22\", \"\", $custom_id),\n        \'glz_custom_date-picker_field clearfix\'\n      );\n    \n    case \"time-picker\":\n      return array(\n        fInput(\"text\", $custom, $custom_value, \"edit time-picker\", \"\", \"\", \"22\", \"\", $custom_id),\n        \'glz_custom_time-picker_field\'\n      );\n    \n    case \"custom-script\":\n      return array(\n        glz_custom_script(reset($arr_custom_field_values), $custom, $custom_id, $custom_value),\n        \'glz_custom_field_script\'\n      );\n\n    // a type has been passed that is not supported yet\n    default:\n      return array(\n        glz_custom_fields_gTxt(\'type_not_supported\'),\n        \'glz_custom_field\'\n      );\n  }\n}\n\n\n// -------------------------------------------------------------\n// had to duplicate the default selectInput() because trimming \\t and \\n didn\'t work + some other mods & multi-select\nfunction glz_selectInput($name = \'\', $id = \'\', $arr_values = \'\', $custom_value = \'\', $default_value = \'\', $multi = \'\') {\n  if ( is_array($arr_values) ) {\n    global $prefs;\n    $out = array();\n\n    // if there is no custom_value coming from the article, let\'s use our default one\n    if ( empty($custom_value) )\n      $custom_value = $default_value;\n\n    foreach ($arr_values as $key => $value) {\n      $selected = glz_selected_checked(\'selected\', $key, $custom_value, $default_value);\n      $out[] = \"<option value=\\\"$key\\\"{$selected}>$value</option>\";\n    }\n\n    // we\'ll need the extra attributes as well as a name that will produce an array\n    if ($multi) {\n      $multi = \' multiple=\"multiple\" size=\"\'.$prefs[\'multiselect_size\'].\'\"\';\n      $name .= \"[]\";\n    }\n\n    return \"<select id=\\\"\".glz_idify($id).\"\\\" name=\\\"$name\\\" class=\\\"list\\\"$multi>\".\n      ($default_value ? \'\' : \"<option value=\\\"\\\"$selected>&nbsp;</option>\").\n      ( $out ? join(\'\', $out) : \'\').\n      \"</select>\";\n  }\n  else\n    return glz_custom_fields_gTxt(\'field_problems\', array(\'{custom_set_name}\' => $name));\n}\n\n\n// -------------------------------------------------------------\n// had to duplicate the default checkbox() to keep the looping in here and check against existing value/s\nfunction glz_checkbox($name = \'\', $arr_values = \'\', $custom_value = \'\', $default_value = \'\') {\n  if ( is_array($arr_values) ) {\n    $out = array();\n\n    // if there is no custom_value coming from the article, let\'s use our default one\n    if ( empty($custom_value) )\n      $custom_value = $default_value;\n\n    foreach ( $arr_values as $key => $value ) {\n      $checked = glz_selected_checked(\'checked\', $key, $custom_value);\n\n      // Putting an additional span around the input and label combination so the two can be floated together as a pair for left-right, left-right,... arrangement of checkboxes and radio buttons. Thanks Julian!\n      $out[] = \"<span><input type=\\\"checkbox\\\" name=\\\"{$name}[]\\\" value=\\\"$key\\\" class=\\\"checkbox\\\" id=\\\"\".glz_idify($key).\"\\\"{$checked} /><label for=\\\"\".glz_idify($key).\"\\\">$value</label></span><br />\";\n    }\n\n    return join(\'\', $out);\n  }\n  else\n    return glz_custom_fields_gTxt(\'field_problems\', array(\'{custom_set_name}\' => $name));\n}\n\n\n// -------------------------------------------------------------\n// had to duplicate the default radio() to keep the looping in here and check against existing value/s\nfunction glz_radio($name = \'\', $id = \'\', $arr_values = \'\', $custom_value = \'\', $default_value = \'\') {\n  if ( is_array($arr_values) ) {\n    $out = array();\n\n    // if there is no custom_value coming from the article, let\'s use our default one\n    if ( empty($custom_value) )\n      $custom_value = $default_value;\n\n    foreach ( $arr_values as $key => $value ) {\n      $checked = glz_selected_checked(\'checked\', $key, $custom_value);\n\n      // Putting an additional span around the input and label combination so the two can be floated together as a pair for left-right, left-right,... arrangement of checkboxes and radio buttons. Thanks Julian!\n      $out[] = \"<span><input type=\\\"radio\\\" name=\\\"$name\\\" value=\\\"$key\\\" class=\\\"radio\\\" id=\\\"{$id}_\".glz_idify($key).\"\\\"{$checked} /><label for=\\\"{$id}_\".glz_idify($key).\"\\\">$value</label></span><br />\";\n    }\n\n    return join(\'\', $out);\n  }\n  else\n    return glz_custom_fields_gTxt(\'field_problems\', array(\'{custom_set_name}\' => $name));\n}\n\n\n// -------------------------------------------------------------\n// checking if this custom field has selected or checked values\nfunction glz_selected_checked($nomenclature, $value, $custom_value = \'\') {\n  // we\'re comparing against a key which is a \"clean\" value\n  $custom_value = htmlspecialchars($custom_value);\n\n  // make an array if $custom_value contains multiple values\n  if ( strpos($custom_value, \'|\') )\n    $arr_custom_value = explode(\'|\', $custom_value);\n\n  if ( isset($arr_custom_value) )\n    $out = ( in_array($value, $arr_custom_value) ) ? \" $nomenclature=\\\"$nomenclature\\\"\" : \"\";\n  else\n    $out = ($value == $custom_value) ? \" $nomenclature=\\\"$nomenclature\\\"\" : \"\";\n\n  return $out;\n}\n\n\n//-------------------------------------------------------------\n// button gets more consistent styling across browsers rather than input type=\"submit\"\n// included in this plugin until in makes it into TXP - if that ever happens...\nfunction glz_fButton($type, $name, $contents=\'Submit\', $value, $class=\'\', $id=\'\', $title=\'\', $onClick=\'\', $disabled = false) {\n  $o  = \'<button type=\"\'.$type.\'\" name=\"\'.$name.\'\"\';\n  $o .= \' value=\"\'.htmlspecialchars($value).\'\"\';\n  $o .= ($class)    ? \' class=\"\'.$class.\'\"\' : \'\';\n  $o .= ($id)       ? \' id=\"\'.$id.\'\"\' : \'\';\n  $o .= ($title)    ? \' title=\"\'.$title.\'\"\' : \'\';\n  $o .= ($onClick)  ? \' onclick=\"\'.$onClick.\'\"\' : \'\';\n  $o .= ($disabled) ? \' disabled=\"disabled\"\' : \'\';\n  $o .= \'>\';\n  $o .= $contents;\n  $o .= \'</button>\';\n  return $o;\n}\n\n\n//-------------------------------------------------------------\n// evals a PHP script and displays output right under the custom field label\nfunction glz_custom_script($script, $custom, $custom_id, $custom_value) {\n  if ( is_file($script) ) {\n    include($script);\n    $custom_function = basename($script, \".php\");\n    if ( is_callable($custom_function) ) {\n      return call_user_func_array($custom_function, array($custom, $custom_id, $custom_value));\n    }\n    else\n      return glz_custom_fields_gTxt(\'not_callable\', array(\'{function}\' => $custom_function, \'{file}\' => $script));\n  }\n  else\n    return glz_custom_fields_gTxt(\'not_found\', array(\'{file}\' => $script));\n\n}\n\n\n// -------------------------------------------------------------\n// PHP4 doesn\'t come with array_combine... Thank you redbot!\nfunction php4_array_combine($keys, $values) {\n  $result = array(); // initializing the array\n\n  foreach ( array_map(null, $keys, $values) as $pair ) {\n    $result[$pair[0]] = $pair[1];\n  }\n\n  return $result;\n}\n\n\n// -------------------------------------------------------------\n// converts all values into id safe ones\nfunction glz_idify($value) {\n  $patterns[0] = \"/\\s/\";\n  $replacements[0] = \"-\";\n  $patterns[1] = \"/[^a-zA-Z0-9\\-]/\";\n  $replacements[1] = \"\";\n\n  return preg_replace($patterns, $replacements, strtolower($value));\n}\n\n\n// -------------------------------------------------------------\n// strips slashes in arrays, used in conjuction with e.g. array_map\nfunction glz_array_stripslashes(&$value) {\n  return stripslashes($value);\n}\n\n\n// -------------------------------------------------------------\n// returns all sections/categories that are searchable\nfunction glz_all_searchable_sections_categories($type) {\n  $type = (in_array($type, array(\'category\', \'section\')) ? $type : \'section\');\n  $condition = \"\";\n\n  if ( $type == \"section\" )\n    $condition .= \"searchable=\'1\'\";\n  else\n    $condition .= \"name <> \'root\' AND type=\'article\'\";\n\n  $result = safe_rows(\'*\', \"txp_{$type}\", $condition);\n\n  $out = array();\n  foreach ($result as $value) {\n    $out[$value[\'name\']] = $value[\'title\'];\n  }\n\n  return $out;\n}\n\n// -------------------------------------------------------------\n// will leave only [A-Za-z0-9 ] in the string\nfunction glz_clean_string($string) {\n  if ($string)\n    return preg_replace(\'/[^A-Za-z0-9\\s\\_\\-]/\', \'\', $string);\n}\n\n\n\n\n\n// -------------------------------------------------------------\n// replaces the default custom fields under write tab\nfunction glz_custom_fields_replace($event, $step, $data, $rs) {\n  global $all_custom_sets, $date_picker;\n  // get all custom fields & keep only the ones which are set, filter by step\n  $arr_custom_fields = glz_check_custom_set($all_custom_sets, $step);\n\n  // DEBUG\n  // dmp($arr_custom_fields);\n\n  $out = \' \';\n\n  if ( is_array($arr_custom_fields) && !empty($arr_custom_fields) ) {\n    // get all custom fields values for this article\n    $arr_article_customs = glz_custom_fields_MySQL(\"article_customs\", glz_get_article_id(), \'\', $arr_custom_fields);\n\n    // DEBUG\n    // dmp($arr_article_customs);\n\n    if ( is_array($arr_article_customs) )\n      extract($arr_article_customs);\n\n    // let\'s see which custom fields are set\n    foreach ( $arr_custom_fields as $custom => $custom_set ) {\n      // get all possible/default value(s) for this custom set from custom_fields table\n      $arr_custom_field_values = glz_custom_fields_MySQL(\"values\", $custom, \'\', array(\'custom_set_name\' => $custom_set[\'name\']));\n\n      // DEBUG\n      // dmp($arr_custom_field_values);\n\n      //custom_set formatted for id e.g. custom_1_set => custom-1 - don\'t ask...\n      $custom_id = glz_custom_number($custom, \"-\");\n      //custom_set without \"_set\" e.g. custom_1_set => custom_1\n      $custom = glz_custom_number($custom);\n\n      // if current article holds no value for this custom field and we have no default value, make it empty\n      $custom_value = (!empty($$custom) ? $$custom : \'\');\n      // DEBUG\n      // dmp(\"custom_value: {$custom_value}\");\n\n      // check if there is a default value\n      // if there is, strip the { }\n      $default_value = glz_return_clean_default(glz_default_value($arr_custom_field_values));\n      // DEBUG\n      // dmp(\"default_value: {$default_value}\");\n\n      // now that we\'ve found our default, we need to clean our custom_field values\n      if (is_array($arr_custom_field_values))\n        array_walk($arr_custom_field_values, \"glz_clean_default_array_values\");\n\n      // DEBUG\n      // dmp($arr_custom_field_values);\n\n      // the way our custom field value is going to look like\n      list($custom_set_value, $custom_class) = glz_format_custom_set_by_type($custom, $custom_id, $custom_set[\'type\'], $arr_custom_field_values, $custom_value, $default_value);\n\n      // DEBUG\n      // dmp($custom_set_value);\n\n      $out .= graf(\n        \"<label for=\\\"$custom_id\\\">{$custom_set[\'name\']}</label><br />$custom_set_value\", \" class=\\\"$custom_class\\\"\"\n      );\n    }\n  }\n\n  // DEBUG\n  // dmp($out);\n\n  // if we\'re writing textarea custom fields, we need to include the excerpt as well\n  if ($step == \"excerpt\")\n    $out = $data.$out;\n\n  return $out;\n}\n\n\n// -------------------------------------------------------------\n// prep our custom fields for the db (watch out for multi-selects, checkboxes & radios, they might have multiple values)\nfunction glz_custom_fields_before_save() {\n  // keep only the custom fields\n  foreach ($_POST as $key => $value) {\n    //check for custom fields with multiple values e.g. arrays\n    if ( strstr($key, \'custom_\') && is_array($value) ) {\n      $value = implode($value, \'|\');\n      // feed our custom fields back into the $_POST\n      $_POST[$key] = $value;\n    }\n  }\n  // DEBUG\n  // dmp($_POST);\n}\n\n\n// -------------------------------------------------------------\n// adds the css & js we need\nfunction glz_custom_fields_css_js() {\n  global $glz_notice, $date_picker, $time_picker, $prefs;\n\n  // here come our custom stylesheetz\n  $css = <<<EOF\n<style type=\"text/css\" media=\"all\">\n/* - - - - - - - - - - - - - - - - - - - - -\n\n### TEXTPATTERN CUSTOM FIELDS ###\n\nTitle : glz_custom_fields stylesheet\nAuthor : Gerhard Lazu\nURL : http://www.gerhardlazu.com/\n\nCreated : 14th May 2007\nLast modified: 28th September 2009\n\n- - - - - - - - - - - - - - - - - - - - - */\n\n.clearfix:after {\n  content: \".\";\n  display: block;\n  clear: both;\n  visibility: hidden;\n  line-height: 0;\n  height: 0;\n}\n\n.clearfix {\n  display: inline-block;\n}\n\nhtml[xmlns] .clearfix {\n  display: block;\n}\n\n* html .clearfix {\n  height: 1%;\n}\n\n/* CLASSES\n-------------------------------------------------------------- */\n.green {\n  color: #6B3;\n}\n.red {\n  color: #C00;\n}\n.grey {\n  color: #777;\n}\n.left {\n  float: left;\n}\n.right {\n  float: right;\n}\n\n\n/* TABLE\n-------------------------------------------------------------- */\n.glz_custom_fields {\n  margin: 0 auto;\n  border: 1px solid #DDD;\n  width: 600px;\n}\n\n.glz_custom_fields thead tr {\n  font-size: 1.1em;\n  font-weight: 700;\n  background: #DDD;\n}\n\n.glz_custom_fields tbody tr.alt {\n  background: #EEE;\n}\n\n.glz_custom_fields td {\n  padding: 2px 10px;\n  vertical-align: middle;\n}\n.glz_custom_fields thead td {\n  padding: 2px 8px 3px 8px;\n}\n.glz_custom_fields td.custom_set_position {\n  text-align: right;\n  width: 10%;\n}\n.glz_custom_fields td.custom_set_name {\n  width: 30%;\n}\n.glz_custom_fields td.type {\n  width: 30%;\n}\n.glz_custom_fields td.events {\n  width: 30%;\n  text-align: right;\n}\n\n.glz_custom_fields_prefs {\n  width: 500px;\n}\n.glz_custom_fields_prefs#list tr th {\n  font-weight: normal;\n  text-align: right;\n  vertical-align: top;\n  width: 50%;\n}\n.glz_custom_fields_prefs#list tr.heading td {\n  padding-top: 30px;\n}\n.glz_custom_fields_prefs#list tr.heading td h2 {\n  margin-top: 0\n}\n.glz_custom_fields_prefs tr td select,\n.glz_custom_fields_prefs tr td input {\n  width: 100%;\n}\n.glz_custom_fields_prefs tr td input.publish {\n  margin-left: 51%;\n  width: auto;\n}\n\n\n\n/* FORMS\n-------------------------------------------------------------- */\n.glz_custom_fields td.events form {\n  display: inline;\n}\n\n#add_edit_custom_field {\n  width: 600px;\n  margin: 2em auto 0 auto;\n}\n#add_edit_custom_field fieldset {\n  padding: 10px;\n}\n#add_edit_custom_field legend {\n  font-size: 1.1em;\n  font-weight: 700;\n}\n#add_edit_custom_field label {\n  width: 20%;\n  font-weight: 700;\n}\n#add_edit_custom_field p input,\n#add_edit_custom_field p select {\n  width: 50%;\n}\n#add_edit_custom_field p textarea {\n  font-size: 0.9em;\n  padding: 1px 0 1px 3px;\n  width: 50%; height: 100px;\n}\n#add_edit_custom_field p span {\n  padding-top: 3px;\n  width: 27%;\n}\n#add_edit_custom_field p em,\n.glz_custom_fields_prefs tr em {\n  font-size: 0.9em;\n  font-weight: 500;\n}\n#add_edit_custom_field input.publish {\n  margin-left: 117px;\n}\n\n/* select on write tab for the custom fields */\ntd#article-col-1 #advanced p select.list {\n  width: 100%;\n}\n\ntd#article-col-1 #advanced p input.radio,\ntd#article-col-1 #advanced p input.checkbox {\n  width: auto;\n}\n</style>\nEOF;\n  // and here come our javascriptz\n  $js = \'\';\n  $date_picker_js = \'\';\n  if ( $date_picker ) {\n    $css .= \'<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"\'.$prefs[\'datepicker_url\'].\'datePicker.css\" />\'.n;\n    foreach (array(\'date.js\', \'datePicker.js\') as $file) {\n      $js .= \'<script type=\"text/javascript\" src=\"\'.$prefs[\'datepicker_url\'].$file.\'\"></script>\'.n;\n    }\n    $date_picker_js = <<<EOF\ntry {\n  Date.firstDayOfWeek = {$prefs[\'datepicker_first_day\']};\n  Date.format = \'{$prefs[\'datepicker_format\']}\';\n  Date.fullYearStart = \'19\';\n  $(\".date-picker\").datePicker({startDate:\'{$prefs[\'datepicker_start_date\']}\'});\n} catch(err) {\n  $(\'#messagepane\').html(\'<a href=\"http://{$prefs[\'siteurl\']}/textpattern/?event=plugin_prefs.glz_custom_fields\">Fix glz_custom_fields configuration</a>\');\n}\nEOF;\n  }\n  $time_picker_js = \'\';\n  if ( $time_picker ) {\n    $css .= \'<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"\'.$prefs[\'timepicker_url\'].\'timePicker.css\" />\'.n;\n    $js .= \'<script type=\"text/javascript\" src=\"\'.$prefs[\'timepicker_url\'].\'timePicker.js\"></script>\'.n;\n    $time_picker_js = <<<EOF\ntry {\n  $(\".time-picker\").timePicker({\n    startTime:\'{$prefs[\'timepicker_start_time\']}\',\n    endTime: \'{$prefs[\'timepicker_end_time\']}\',\n    step: {$prefs[\'timepicker_step\']},\n    show24Hours: {$prefs[\'timepicker_show_24\']}\n  });\n} catch(err) {\n  $(\'#messagepane\').html(\'<a href=\"http://{$prefs[\'siteurl\']}/textpattern/?event=plugin_prefs.glz_custom_fields\">Fix glz_custom_fields configuration</a>\');\n} \nEOF;\n  }\n  $js .= <<<EOF\n<script type=\"text/javascript\">\n<!--//--><![CDATA[//><!--\n\n$(function() {\n  // creating a global object to store variables, functions etc.\n  var GLZ_CUSTOM_FIELDS;\n  if (GLZ_CUSTOM_FIELDS == undefined)\n    GLZ_CUSTOM_FIELDS = {};\n  GLZ_CUSTOM_FIELDS.special_custom_types = [\"date-picker\", \"time-picker\"];\n  GLZ_CUSTOM_FIELDS.no_value_custom_types = [\"text_input\", \"textarea\"];\n  GLZ_CUSTOM_FIELDS.messages = {\n    \'textarea\' : \"<em>Each value on a separate line</em><br /><em>One {default} value allowed</em>\",\n    \'script\' : \"<em>Full path to your script</em>\"\n  }\n\n  // sweet jQuery table striping\n  $(\".stripeMe tr\").mouseover(function() { $(this).addClass(\"over\"); }).mouseout(function() { $(this).removeClass(\"over\"); });\n  $(\".stripeMe tr:even\").addClass(\"alt\");\n\n  // disable all custom field references in Advanced Prefs\n  // prefs_ui doesn\'t offer support for this, getting the custom fields to display right here is not crucial at this point\n  var custom_field_tr = $(\"tr[id*=prefs-custom_], tr:has(h2:contains(\'Custom Fields\'))\").not(\'.glz_custom_fields_prefs tr:has(h2)\');\n  if ( custom_field_tr ) {\n    $.each (custom_field_tr, function() {\n      $(this).hide();\n    });\n  }\n\n  // toggle custom field value based on its type\n  \n  toggle_type_link();\n  if ( $.inArray($(\"select#custom_set_type :selected\").attr(\"value\"), [].concat(GLZ_CUSTOM_FIELDS.special_custom_types, GLZ_CUSTOM_FIELDS.no_value_custom_types)) != -1 ) {\n    custom_field_value_off();\n  }\n  else if ( $(\"select#custom_set_type :selected\").attr(\"value\") == \"custom-script\" )\n    custom_field_value_path();\n\n  $(\"select#custom_set_type\").change( function() {\n    toggle_type_link();\n    if ( $.inArray($(\"select#custom_set_type :selected\").attr(\"value\"), [].concat(GLZ_CUSTOM_FIELDS.special_custom_types, GLZ_CUSTOM_FIELDS.no_value_custom_types)) != -1 ) {\n      custom_field_value_off();\n    }\n    else if ( $(\"select#custom_set_type :selected\").attr(\"value\") == \"custom-script\" )\n      custom_field_value_path();\n    else {\n      custom_field_value_on();\n    }\n  });\n\n  // enable date-picker custom sets\n  {$date_picker_js}\n  \n  // enable time-picker custom sets\n  {$time_picker_js}\n\n  // add a reset link to all radio custom fields\n  if ($(\".glz_custom_radio_field\").length > 0) {\n    $(\".glz_custom_radio_field\").each(function() {\n      custom_field_to_reset = $(this).find(\"input:first\").attr(\"name\");\n      $(this).find(\"label:first\").after(\" <span class=\\\"small\\\">[<a href=\\\"#\\\" class=\\\"glz_custom_field_reset\\\" name=\\\"\" + custom_field_to_reset +\"\\\">Reset</a>]</span>\");\n    });\n\n    // catch the reset action for the above link\n    $(\".glz_custom_field_reset\").click(function() {\n      custom_field_to_reset = $(this).attr(\"name\");\n      // reset our radio input\n      $(\"input[name=\" + custom_field_to_reset + \"]\").attr(\"checked\", false);\n      // add an empty value with the same ID so that it saves the value as empty in the db\n      $(this).after(\"<input type=\\\"hidden\\\" value=\\\"\\\" name=\\\"\"+ custom_field_to_reset +\"\\\" />\");\n      return false;\n    });\n  }\n\n  // ### RE-USABLE FUNCTIONS ###\n\n  function custom_field_value_off() {\n    if ($(\"textarea#value\").length) {\n      GLZ_CUSTOM_FIELDS.textarea_value = $(\"textarea#value\").html();\n      $(\"textarea#value + span.right\").html(\'\');\n      $(\"textarea#value\").remove();\n    }\n    \n    if (!$(\"input#value\").length)\n      $(\"label[for=value]\").after(\'<input id=\"value\" name=\"value\" class=\"left\" />\');\n    $(\"input#value\").attr(\'value\', \"no value allowed\").attr(\'disabled\', \"disabled\");\n    $(\"input#value + span.right\").html(\'\');\n  }\n\n  function custom_field_value_on() {\n    if ( $(\"input#value\").length )\n      $(\"input#value\").remove();\n    if ( !$(\"textarea#value\").length ) {\n      $(\"label[for=value]\").after(\'<textarea id=\"value\" name=\"value\" class=\"left\"></textarea>\');\n      $(\"textarea#value + span.right\").html(GLZ_CUSTOM_FIELDS.messages[\'textarea\']);\n    }\n    if ( GLZ_CUSTOM_FIELDS.textarea_value )\n      $(\"textarea#value\").html(GLZ_CUSTOM_FIELDS.textarea_value);\n  }\n\n  function custom_field_value_path() {\n    if ($(\"textarea#value\").length) {\n      $(\"textarea#value + span.right\").html(\'\');\n      $(\"textarea#value\").remove();\n    }\n    if (!$(\"input#value\").length)\n      $(\"label[for=value]\").after(\'<input id=\"value\" name=\"value\" class=\"left\" />\');\n    if ( $.inArray($(\"input#value\").attr(\'value\'), [\"\", \"no value allowed\"]) != -1 )\n      $(\"input#value\").attr(\'value\', \"{$prefs[\'custom_scripts_path\']}\")\n    $(\"input#value\").attr(\'disabled\', \"\");\n    $(\"input#value + span.right\").html(GLZ_CUSTOM_FIELDS.messages[\'script\']);\n  }\n\n  function toggle_type_link() {\n    $(\"select#custom_set_type\").parent().find(\'span\').remove();\n    if ( $.inArray($(\"select#custom_set_type :selected\").attr(\"value\"), [].concat(GLZ_CUSTOM_FIELDS.special_custom_types, [\"multi-select\"])) != -1 )\n      $(\"select#custom_set_type\").after(\"<span class=\\\"right\\\"><em><a href=\\\"http://{$prefs[\'siteurl\']}/textpattern?event=plugin_prefs.glz_custom_fields\\\">Configure glz_custom_fields</a></em></span>\");\n  }\n\n});\n\n//--><!]]>\n</script>\nEOF;\n\n  // displays the notices we have gathered throughout the entire plugin\n  if ( count($glz_notice) > 0 ) {\n    // let\'s turn our notices into a string\n    $glz_notice = join(\"<br />\", array_unique($glz_notice));\n\n    $js .= \'<script type=\"text/javascript\">\n    <!--//--><![CDATA[//><!--\n\n    $(document).ready(function() {\n      // add our notices\n      $(\"#messagepane\").html(\\\'\'.$glz_notice.\'\\\');\n    });\n    //--><!]]>\n    </script>\';\n  }\n\n  echo $js.n.t.$css.n.t;\n}\n\n\n// -------------------------------------------------------------\n// we are setting up the pre-requisite values for glz_custom_fields\nfunction before_glz_custom_fields() {\n  // we will be reusing these globals across the whole plugin\n  global $all_custom_sets, $glz_notice, $prefs, $date_picker, $time_picker;\n\n  // glz_notice collects all plugin notices\n  $glz_notice = array();\n\n  // let\'s get all custom field sets from prefs\n  $all_custom_sets = glz_custom_fields_MySQL(\"all\");\n\n  // let\'s see if we have a date-picker custom field (first of the special ones)\n  $date_picker = glz_custom_fields_MySQL(\"custom_set_exists\", \"date-picker\");\n  \n  // let\'s see if we have a time-picker custom field\n  $time_picker = glz_custom_fields_MySQL(\"custom_set_exists\", \"time-picker\");\n}\n\n\n// -------------------------------------------------------------\n// bootstrapping routines, run through plugin_lifecycle\nfunction glz_custom_fields_install() {\n  global $all_custom_sets, $glz_notice, $prefs;\n\n  // if jQuery is not present, trigger error\n  // improvement courtesy of Sam Weiss\n  if ( !@fopen($GLOBALS[\'txpcfg\'][\'txpath\'].\'/jquery.js\', \"r\") ) {\n    trigger_error(glz_custom_fields_gTxt(\'jquery_missing\'));\n    trigger_error(glz_custom_fields_gTxt(\'check_path\'));\n  }\n\n  // default custom fields are set to custom_set\n  // need to change this because it confuses our set_types()\n  safe_query(\"\n    UPDATE\n      `\".PFX.\"txp_prefs`\n    SET\n      `html` = \'text_input\'\n    WHERE\n      `event` = \'custom\'\n    AND\n      `html` = \'custom_set\'\n  \");\n\n  // set plugin preferences\n  $arr_plugin_preferences = array(\n    \'values_ordering\'       => \"custom\",\n    \'multiselect_size\'      => \"5\",\n    \'datepicker_url\'        => hu.\"scripts/glz_custom_fields/jquery.datePicker/\",\n    \'datepicker_format\'     => \"dd/mm/yyyy\",\n    \'datepicker_first_day\'  => 1,\n    \'datepicker_start_date\' => \"01/01/1990\",\n    \'timepicker_url\'        => hu.\"scripts/glz_custom_fields/jquery.timePicker/\",\n    \'timepicker_start_time\' => \"00:00\",\n    \'timepicker_end_time\'   => \"23:30\",\n    \'timepicker_step\'       => 30,\n    \'timepicker_show_24\'    => true,\n    \'custom_scripts_path\'   => $prefs[\'path_to_site\'].\"/scripts/glz_custom_fields/\",\n  );\n  glz_custom_fields_MySQL(\"update_plugin_preferences\", $arr_plugin_preferences);\n\n  // let\'s update plugin preferences, make sure they won\'t appear under Admin > Preferences\n  safe_query(\"\n    UPDATE\n      `\".PFX.\"txp_prefs`\n    SET\n      `type` = \'10\'\n    WHERE\n      `event` = \'glz_custom_f\'\n  \");\n\n  // if we don\'t have a search section, let\'s create it because we\'ll need it when searching by custom fields\n  if( !getRow(\"SELECT name FROM `\".PFX.\"txp_section` WHERE name=\'search\'\") ) {\n    safe_query(\"\n      INSERT INTO\n        `\".PFX.\"txp_section` (`name`, `page`, `css`, `is_default`, `in_rss`, `on_frontpage`, `searchable`, `title`)\n      VALUES\n        (\'search\', \'default\', \'default\', \'0\', \'0\', \'0\', \'0\', \'Search\')\n    \");\n    // add a notice that search section has bee created\n    $glz_notice[] = glz_custom_fields_gTxt(\"search_section_created\");\n  }\n\n  // if we don\'t have the custom_fields table, let\'s create it\n  if ( !getRows(\"SHOW TABLES LIKE \'\".PFX.\"custom_fields\'\") ) {\n   safe_query(\"\n     CREATE TABLE `\".PFX.\"custom_fields` (\n      `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,\n       `name` varchar(255) NOT NULL default \'\',\n       `value` varchar(255) NOT NULL default \'\',\n       PRIMARY KEY (id),\n       INDEX (`name`)\n     ) TYPE=MyISAM\n   \");\n  }\n  else {\n    // if there isn\'t and id column, add it\n    if ( !getRows(\"SHOW COLUMNS FROM \".PFX.\"custom_fields LIKE \'id\'\") ) {\n      safe_query(\"\n        ALTER TABLE `\".PFX.\"custom_fields`\n          ADD `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT KEY\n      \");\n    }\n\n   // if we have definitely migrated using this function, skip everything\n   if ( isset($prefs[\'migrated\']) )\n     return;\n   // abort the migration if there are values in custom_fields table, we don\'t want to overwrite anything\n   else if ( glz_custom_fields_MySQL(\'check_migration\') > 0 ) {\n     // DEBUG\n     // dmp(glz_custom_fields_MySQL(\'check_migration\'));\n     $glz_notice[] = glz_custom_fields_gTxt(\"migration_skip\");\n     // make a note of this migration in txp_prefs\n     glz_custom_fields_MySQL(\'mark_migration\');\n     return;\n   }\n\n   // go through all values in custom field columns in textpattern table one by one\n   foreach ($all_custom_sets as $custom => $custom_set) {\n     // check only for custom fields that have been set\n     if ( $custom_set[\'name\'] ) {\n       // get all existing custom values for ALL articles\n       $all_values = glz_custom_fields_MySQL(\'all_values\', glz_custom_number($custom), \'\', array(\'custom_set_name\' => $custom_set[\'name\'], \'status\' => 0));\n       // if we have results, let\'s create SQL queries that will add them to custom_fields table\n       if ( count($all_values) > 0 ) {\n         // initialize insert\n         $insert = \'\';\n         foreach ( $all_values as $escaped_value => $value ) {\n           // don\'t insert empty values or values that are over 255 characters\n           // values over 255 characters hint to a textarea custom field\n           if ( !empty($escaped_value) && strlen($escaped_value) < 255 )\n             // if this is the last value, query will have to be different\n             $insert .= ( end($all_values) != $value ) ?\n               \"(\'{$custom}\',\'{$escaped_value}\'),\" :\n               \"(\'{$custom}\',\'{$escaped_value}\')\";\n         }\n         $query = \"\n           INSERT INTO\n             `\".PFX.\"custom_fields` (`name`,`value`)\n           VALUES\n             {$insert}\n         \";\n         if ( isset($query) && !empty($query) ) {\n           // create all custom field values in custom_fields table\n           safe_query($query);\n           // update the type of this custom field to select (might want to make this user-adjustable at some point)\n           glz_custom_fields_MySQL(\"update\", $custom, PFX.\"txp_prefs\", array(\n             \'custom_set_name\'   => $custom_set[\'name\'],\n             \'custom_set_type\'   => \"select\",\n             \'custom_set_position\' => $custom_set[\'position\']\n           ));\n           $glz_notice[] = glz_custom_fields_gTxt(\"migration_success\");\n         }\n       }\n     }\n   }\n\n   // make a note of this migration in txp_prefs\n   glz_custom_fields_MySQL(\'mark_migration\');\n  }\n}\n\n\n\n\n\n// globals, expensive operations mostly\nbefore_glz_custom_fields();\n\nif (@txpinterface == \"admin\") {\n\n  // INSTALL ROUTINES\n  // checks if all tables exist and everything is setup properly\n  add_privs(\'glz_custom_fields_install\', \"1\");\n  register_callback(\"glz_custom_fields_install\", \"plugin_lifecycle.glz_custom_fields\", \"installed\");\n\n  // we\'ll be doing this only on the pages that we care about, not everywhere\n  if ( in_array(gps(\'event\'), array(\"article\", \"prefs\", \"glz_custom_fields\", \"plugin_prefs.glz_custom_fields\")) ) {\n    // we need some stylesheets & JS\n    add_privs(\'glz_custom_fields_css_js\', \"1,2,3,4,5,6\");\n    register_callback(\'glz_custom_fields_css_js\', \"admin_side\", \'head_end\');\n\n    // we need to make sure that all custom field values will be converted to strings first - think checkboxes & multi-selects etc.\n    if ( (gps(\"step\") == \"edit\") || (gps(\"step\") == \"create\") ) {\n      add_privs(\'glz_custom_fields_before_save\', \"1,2,3,4,5,6\");\n      register_callback(\'glz_custom_fields_before_save\', \"article\", \'\', 1);\n    }\n  }\n\n  // Custom Fields tab under Extensions\n  add_privs(\'glz_custom_fields\', \"1,2\");\n  register_tab(\"extensions\", \'glz_custom_fields\', \"Custom Fields\");\n  register_callback(\'glz_custom_fields\', \"glz_custom_fields\");\n\n  // plugin preferences\n  add_privs(\'plugin_prefs.glz_custom_fields\', \"1,2\");\n  register_callback(\'glz_custom_fields_preferences\', \'plugin_prefs.glz_custom_fields\');\n\n\n  // YES, finally the default custom fields are replaced by the new, pimped ones : )\n  add_privs(\'glz_custom_fields_replace\', \"1,2,3,4,5,6\");\n  register_callback(\'glz_custom_fields_replace\', \'article_ui\', \'custom_fields\');\n  // YES, now we have textarea custom fields as well ; )\n  add_privs(\'glz_custom_fields_replace\', \"1,2,3,4,5,6\");\n  register_callback(\'glz_custom_fields_replace\', \'article_ui\', \'excerpt\');\n}\n\n// -------------------------------------------------------------\n// everything is happening in this function... generates the content for Extensions > Custom Fields\nfunction glz_custom_fields() {\n  global $event, $all_custom_sets, $glz_notice, $prefs;\n\n  // we have $_POST, let\'s see if there is any CRUD\n  if ( $_POST ) {\n    $incoming = stripPost();\n    // DEBUG\n    // die(dmp($incoming));\n    extract($incoming);\n\n    // create an empty $value if it\'s not set in the $_POST\n    if ( !isset($value) )\n      $value = \'\';\n\n    // we are deleting a new custom field\n    if ( gps(\'delete\') ) {\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"txp_prefs\");\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"txp_lang\");\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"custom_fields\");\n\n      glz_custom_fields_MySQL(\"delete\", glz_custom_number($custom_set), PFX.\"textpattern\");\n\n      $glz_notice[] = glz_custom_fields_gTxt(\"deleted\", array(\'{custom_set_name}\' => $custom_set_name));\n    }\n\n    // we are resetting one of the mighty 10\n    if ( gps(\'reset\') ) {\n      glz_custom_fields_MySQL(\"reset\", $custom_set, PFX.\"txp_prefs\");\n      glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"custom_fields\");\n\n      glz_custom_fields_MySQL(\"reset\", glz_custom_number($custom_set), PFX.\"textpattern\", array(\n        \'custom_set_type\' => $custom_set_type,\n        \'custom_field\' => glz_custom_number($custom_set)\n      ));\n\n      $glz_notice[] = glz_custom_fields_gTxt(\"reset\", array(\'{custom_set_name}\' => $custom_set_name));\n    }\n\n    // we are adding a new custom field\n    if ( gps(\"custom_field_number\") ) {\n      $custom_set_name = gps(\"custom_set_name\");\n\n      // if no name was specified, abort\n      if ( !$custom_set_name )\n        $glz_notice[] = glz_custom_fields_gTxt(\"no_name\");\n      else {\n        $custom_set_name = glz_clean_string($custom_set_name);\n\n        $name_exists = glz_check_custom_set_name($all_custom_sets, $custom_set_name);\n\n        // if name doesn\'t exist\n        if ( $name_exists == FALSE ) {\n          glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"txp_prefs\", array(\n            \'custom_field_number\' => $custom_field_number,\n            \'custom_set_type\'     => $custom_set_type,\n            \'custom_set_position\' => $custom_set_position\n          ));\n          glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"txp_lang\", array(\n            \'custom_field_number\' => $custom_field_number,\n            \'lang\'                => $GLOBALS[\'prefs\'][\'language\']\n          ));\n          glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"textpattern\", array(\n            \'custom_field_number\' => $custom_field_number,\n            \'custom_set_type\' => $custom_set_type\n          ));\n          // there are custom fields for which we do not need to touch custom_fields table\n          if ( !in_array($custom_set_type, array(\"textarea\", \"text_input\")) ) {\n            glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"custom_fields\", array(\n              \'custom_field_number\' => $custom_field_number,\n              \'value\'               => $value\n            ));\n          }\n\n          $glz_notice[] = glz_custom_fields_gTxt(\"created\", array(\'{custom_set_name}\' => $custom_set_name));\n        }\n        // name exists, abort\n        else\n          $glz_notice[] = glz_custom_fields_gTxt(\"exists\", array(\'{custom_set_name}\' => $custom_set_name));\n      }\n    }\n\n    // we are editing an existing custom field\n    if ( gps(\'save\') ) {\n      if ( !empty($custom_set_name) ) {\n        $custom_set_name = glz_clean_string($custom_set_name);\n        $name_exists = glz_check_custom_set_name($all_custom_sets, $custom_set_name, $custom_set);\n        // if name doesn\'t exist we\'ll need to create a new custom_set\n        if ( $name_exists == FALSE ) {\n          glz_custom_fields_MySQL(\"update\", $custom_set, PFX.\"txp_prefs\", array(\n            \'custom_set_name\'     => $custom_set_name,\n            \'custom_set_type\'     => $custom_set_type,\n            \'custom_set_position\' => $custom_set_position\n          ));\n\n          // custom sets need to be changed based on their type\n          glz_custom_fields_MySQL(\"update\", $custom_set, PFX.\"textpattern\", array(\n            \'custom_set_type\' => $custom_set_type,\n            \'custom_field\' => glz_custom_number($custom_set)\n          ));\n\n          // for textareas we do not need to touch custom_fields table\n          if ( $custom_set_type != \"textarea\" ) {\n            glz_custom_fields_MySQL(\"delete\", $custom_set, PFX.\"custom_fields\");\n            glz_custom_fields_MySQL(\"new\", $custom_set_name, PFX.\"custom_fields\", array(\n              \'custom_set\'  => $custom_set,\n              \'value\'       => $value\n            ));\n          }\n\n          $glz_notice[] = glz_custom_fields_gTxt(\"updated\", array(\'{custom_set_name}\' => $custom_set_name));\n        }\n        // name exists, abort\n        else\n          $glz_notice[] = glz_custom_fields_gTxt(\"exists\", array(\'{custom_set_name}\' => $custom_set_name));\n      }\n      else\n        $glz_notice[] = glz_custom_fields_gTxt(\'no_name\');\n    }\n\n    // need to re-fetch data since things modified\n    $all_custom_sets = glz_custom_fields_MySQL(\"all\");\n\n  }\n\n  pagetop(\"Custom Fields\");\n\n  // the table with all custom fields follows\n  echo\n    n.\'<table cellspacing=\"0\" class=\"glz_custom_fields stripeMe\">\'.n.\n    \' <thead>\'.n.\n    \'   <tr>\'.n.\n    \'     <td>Position</td>\'.n.\n    \'     <td>Name</td>\'.n.\n    \'     <td>Type</td>\'.n.\n    \'     <td>&nbsp;</td>\'.n.\n    \'   </tr>\'.n.\n    \' </thead>\'.n.\n    \' <tbody>\'.n;\n\n  // looping through all our custom fields to build the table\n  $i = 0;\n  foreach ( $all_custom_sets as $custom => $custom_set ) {\n    // first 10 fields cannot be deleted, just reset\n    if ( $i < 10 ) {\n      // can\'t reset a custom field that is not set\n      $reset_delete = ( $custom_set[\'name\'] ) ?\n        glz_form_buttons(\"reset\", \"Reset\", $custom, htmlspecialchars($custom_set[\'name\']), $custom_set[\'type\'], \'\', \'return confirm(\\\'By proceeding you will RESET ALL data in `textpattern` and `custom_fields` tables for `\'.$custom.\'`. Are you sure?\\\');\') :\n        NULL;\n    }\n    else {\n      $reset_delete = glz_form_buttons(\"delete\", \"Delete\", $custom, htmlspecialchars($custom_set[\'name\']), $custom_set[\'type\'], \'\', \'return confirm(\\\'By proceeding you will DELETE ALL data in `textpattern` and `custom_fields` tables for `\'.$custom.\'`. Are you sure?\\\');\');\n    }\n\n    $edit = glz_form_buttons(\"edit\", \"Edit\", $custom, htmlspecialchars($custom_set[\'name\']), $custom_set[\'type\'], $custom_set[\'position\']);\n\n    echo\n    \'   <tr>\'.n.\n    \'     <td class=\"custom_set_position\">\'.$custom_set[\'position\'].\'</td>\'.n.\n    \'     <td class=\"custom_set_name\">\'.$custom_set[\'name\'].\'</td>\'.n.\n    \'     <td class=\"type\">\'.(($custom_set[\'name\']) ? glz_custom_fields_gTxt($custom_set[\'type\']) : \'\').\'</td>\'.n.\n    \'     <td class=\"events\">\'.$reset_delete.sp.$edit.\'</td>\'.n.\n    \'   </tr>\'.n;\n\n    $i++;\n  }\n\n  echo\n    \' </tbody>\'.n.\n    \'</table>\'.n;\n\n  // the form where custom fields are being added/edited\n  $legend = gps(\'edit\') ?\n    \'Edit \'.gps(\'custom_set\') :\n    \'Add new custom field\';\n\n  $custom_field = gps(\'edit\') ?\n    \'<input name=\"custom_set\" value=\"\'.gps(\'custom_set\').\'\" type=\"hidden\" />\' :\n    \'<input name=\"custom_field_number\" value=\"\'.glz_custom_next($all_custom_sets).\'\" type=\"hidden\" />\';\n\n  $custom_set = gps(\'edit\') ?\n    gps(\'custom_set\') :\n    NULL;\n\n  $custom_name = gps(\'edit\') ?\n    gps(\'custom_set_name\') :\n    NULL;\n\n  $custom_set_position = gps(\'edit\') ?\n    gps(\'custom_set_position\') :\n    NULL;\n\n  $arr_custom_set_types = glz_custom_set_types();\n\n  $custom_set_types = NULL;\n  foreach ( $arr_custom_set_types as $custom_type_group => $custom_types ) {\n    $custom_set_types .= \'<optgroup label=\"\'.ucfirst($custom_type_group).\'\">\'.n;\n    foreach ($custom_types as $custom_type) {\n      $selected = ( gps(\'edit\') && gps(\'custom_set_type\') == $custom_type ) ?\n        \' selected=\"selected\"\' :\n        NULL;\n      $custom_set_types .= \'<option value=\"\'.$custom_type.\'\"\'.$selected.\'>\'.glz_custom_fields_gTxt($custom_type).\'</option>\'.n;\n    }\n    $custom_set_types .= \'</optgroup>\'.n;\n  }\n  // fetching the values for this custom field\n  if ( gps(\'edit\') ) {\n    if ( $custom_set_type == \"text_input\" )\n      $arr_values = glz_custom_fields_MySQL(\'all_values\', glz_custom_number($custom_set), \'\', array(\'custom_set_name\' => $custom_set_name, \'status\' => 4));\n    else\n      $arr_values = glz_custom_fields_MySQL(\"values\", $custom_set, \'\', array(\'custom_set_name\' => $custom_set_name));\n    \n    $values = ( $arr_values ) ?\n      implode(\"\\r\\n\", $arr_values) :\n      \'\';\n  }\n  else\n    $values = \'\';\n  \n  $action = gps(\'edit\') ?\n    \'<input name=\"save\" value=\"Save\" type=\"submit\" class=\"publish\" />\' :\n    \'<input name=\"add_new\" value=\"Add new\" type=\"submit\" class=\"publish\" />\';\n  // this needs to be different for a script\n  $value = ( isset($custom_set_type) && $custom_set_type == \"custom-script\" ) ?\n    \'<input name=\"value\" id=\"value\" value=\"\'.$values.\'\" class=\"left\"/><span class=\"right\"><em>Full path to your script</em></span>\' :\n    \'<textarea name=\"value\" id=\"value\" class=\"left\">\'.$values.\'</textarea><span class=\"right\"><em>Each value on a separate line</em> <br /><em>One {default} value allowed</em></span>\';\n  \n  // ok, all is set, let\'s build the form\n  echo\n    \'<form method=\"post\" action=\"index.php\" id=\"add_edit_custom_field\">\'.n.\n    \'<input name=\"event\" value=\"glz_custom_fields\" type=\"hidden\" />\'.n.\n    $custom_field.n.\n    \'<fieldset>\'.n.\n    \' <legend>\'.$legend.\'</legend>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"custom_set_name\" class=\"left\">Name:</label>\n        <input name=\"custom_set_name\" value=\"\'.htmlspecialchars($custom_name).\'\" id=\"custom_set_name\" class=\"left\" />\n        <span class=\"right\"><em>Only word characters allowed</em></span>\n      </p>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"custom_set_type\" class=\"left\">Type:</label>\n        <select name=\"custom_set_type\" id=\"custom_set_type\" class=\"left\">\n    \'.      $custom_set_types.\'\n        </select>\n      </p>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"custom_set_position\" class=\"left\">Position:</label>\n        <input name=\"custom_set_position\" value=\"\'.htmlspecialchars($custom_set_position).\'\" id=\"custom_set_position\" class=\"left\" />\n        <span class=\"right\"><em>Automatically assigned if blank</em></span>\n      </p>\'.n.\n    \' <p class=\"clearfix\">\n        <label for=\"value\" class=\"left\">Value:</label>\n    \'.  $value.\'\n      </p>\'.n.\n    \' \'.$action.n.\n    \'</fieldset>\'.n.\n    \'</form>\'.n;\n}\n\n\n// -------------------------------------------------------------\n// glz_custom_fields preferences\nfunction glz_custom_fields_preferences() {\n  global $event, $glz_notice;\n\n  if ( $_POST && gps(\'save\') ) {\n    glz_custom_fields_MySQL(\"update_plugin_preferences\", $_POST[\'glz_custom_fields_prefs\']);\n    $glz_notice[] = glz_custom_fields_gTxt(\"preferences_updated\");\n    // need to re-fetch from db because this has changed since $prefs has been populated\n  }\n  $current_preferences = glz_custom_fields_MySQL(\'plugin_preferences\');\n\n  pagetop(\"glz_custom_fields Preferences\");\n\n  // custom_fields\n  $arr_values_ordering = array(\n    \'ascending\'   => \"Ascending\",\n    \'descending\'  => \"Descending\",\n    \'custom\'      => \"As entered\"\n  );\n  $values_ordering = \'<select name=\"glz_custom_fields_prefs[values_ordering]\" id=\"glz_custom_fields_prefs_values_ordering\">\';\n  foreach ( $arr_values_ordering as $value => $title ) {\n    $selected = ($current_preferences[\'values_ordering\'] == $value) ? \' selected=\"selected\"\' : \'\';\n    $values_ordering .= \"<option value=\\\"$value\\\"$selected>$title</option>\";\n  }\n  $values_ordering .= \"</select>\";\n  $multiselect_size = \'<input type=\"text\" name=\"glz_custom_fields_prefs[multiselect_size]\" id=\"glz_custom_fields_prefs_multiselect_size\" value=\"\'.$current_preferences[\'multiselect_size\'].\'\" />\';\n  $custom_scripts_path_error = ( @fopen($current_preferences[\'custom_scripts_path\'], \"r\") ) ?\n    \'\' :\n    \'<br /><em class=\"red\">Folder does not exist, please create it.</em>\';\n\n  // jquery.datePicker\n  $datepicker_url_error = ( @fopen($current_preferences[\'datepicker_url\'].\"datePicker.js\", \"r\") ) ?\n    \'\' :\n    \'<br /><em class=\"red\">Folder does not exist, please create it.</em>\';\n  $arr_date_format = array(\"dd/mm/yyyy\", \"mm/dd/yyyy\", \"yyyy-mm-dd\", \"dd mm yy\");\n  $date_format = \'<select name=\"glz_custom_fields_prefs[datepicker_format]\" id=\"glz_custom_fields_prefs_datepicker_format\">\';\n  foreach ( $arr_date_format as $format ) {\n    $selected = ($current_preferences[\'datepicker_format\'] == $format) ? \' selected=\"selected\"\' : \'\';\n    $date_format .= \"<option value=\\\"$format\\\"$selected>$format</option>\";\n  }\n  $date_format .= \"</select>\";\n\n  $arr_days = array(\'Sunday\', \'Monday\', \'Tuesday\', \'Wednesday\', \'Thursday\', \'Friday\', \'Saturday\');\n  $first_day = \'<select name=\"glz_custom_fields_prefs[datepicker_first_day]\" id=\"glz_custom_fields_prefs_datepicker_first_day\">\';\n  foreach ( $arr_days as $key => $day ) {\n    $selected = ($current_preferences[\'datepicker_first_day\'] == $key) ? \' selected=\"selected\"\' : \'\';\n    $first_day .= \"<option value=\\\"$key\\\"$selected>$day</option>\";\n  }\n  $first_day .= \"</select>\";\n\n  $start_date = \'<input type=\"text\" name=\"glz_custom_fields_prefs[datepicker_start_date]\" id=\"glz_custom_fields_prefs_datepicker_start_date\" value=\"\'.$current_preferences[\'datepicker_start_date\'].\'\" />\';\n  \n  // jquery.timePicker\n  $timepicker_url_error = ( @fopen($current_preferences[\'timepicker_url\'].\"timePicker.js\", \"r\") ) ?\n    \'\' :\n    \'<br /><em class=\"red\">Folder does not exist, please create it.</em>\';\n  $arr_time_format = array(\'true\' => \"24 hours\", \'false\' => \"12 hours\");\n  $show_24 = \'<select name=\"glz_custom_fields_prefs[timepicker_show_24]\" id=\"glz_custom_fields_prefs_timepicker_show_24\">\';\n  foreach ( $arr_time_format as $value => $title ) {\n    $selected = ($current_preferences[\'timepicker_show_24\'] == $value) ? \' selected=\"selected\"\' : \'\';\n    $show_24 .= \"<option value=\\\"$value\\\"$selected>$title</option>\";\n  }\n  $show_24 .= \"</select>\";\n\n  $out = <<<EOF\n<form action=\"index.php\" method=\"post\">\n<table id=\"list\" class=\"glz_custom_fields_prefs\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">\n  <tbody>\n    <tr class=\"heading\">\n      <td colspan=\"2\"><h2 class=\"pref-heading\">Custom Fields</h2></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_values_ordering\">Order for custom field values</th>\n      <td>{$values_ordering}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_multiselect_size\">Multi-select field size</th>\n      <td>{$multiselect_size}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_custom_scripts_path\">Custom scripts path</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[custom_scripts_path]\" id=\"glz_custom_fields_prefs_custom_scripts_path\" value=\"{$current_preferences[\'custom_scripts_path\']}\" />{$custom_scripts_path_error}</td>\n    </tr>\n    \n    <tr class=\"heading\">\n      <td colspan=\"2\"><h2 class=\"pref-heading left\">Date Picker</h2> <a href=\"http://www.kelvinluck.com/assets/jquery/datePicker/v2/demo/index.html\" title=\"A flexible unobtrusive calendar component for jQuery\" class=\"right\">jQuery datePicker</a></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_url\">Date Picker plugin URL</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[datepicker_url]\" id=\"glz_custom_fields_prefs_datepicker_url\" value=\"{$current_preferences[\'datepicker_url\']}\" />{$datepicker_url_error}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_format\">Date format</th>\n      <td>{$date_format}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_first_day\">First day of week</th>\n      <td>{$first_day}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_datepicker_start_date\">Start date</th>\n      <td>{$start_date}<br /><em class=\"grey\">MUST be the same as \"Date format\"</em></td>\n    </tr>\n    \n    <tr class=\"heading\">\n      <td colspan=\"2\"><h2 class=\"pref-heading left\">Time Picker</h2> <a href=\"http://labs.perifer.se/timedatepicker/\" title=\"jQuery time picker\" class=\"right\">jQuery timePicker</a></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_url\">Time Picker plugin URL</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_url]\" id=\"glz_custom_fields_prefs_timepicker_url\" value=\"{$current_preferences[\'timepicker_url\']}\" />{$timepicker_url_error}</td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_start_time\">Start time</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_start_time]\" id=\"glz_custom_fields_prefs_timepicker_start_time\" value=\"{$current_preferences[\'timepicker_start_time\']}\" /></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_end_time\">End time</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_end_time]\" id=\"glz_custom_fields_prefs_timepicker_end_time\" value=\"{$current_preferences[\'timepicker_end_time\']}\" /></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_step\">Step</th>\n      <td><input type=\"text\" name=\"glz_custom_fields_prefs[timepicker_step]\" id=\"glz_custom_fields_prefs_timepicker_step\" value=\"{$current_preferences[\'timepicker_step\']}\" /></td>\n    </tr>\n    <tr>\n      <th scope=\"row\"><label for=\"glz_custom_fields_prefs_timepicker_step\">Time format</th>\n      <td>{$show_24}</td>\n    </tr>\n    \n    <tr>\n      <td colspan=\"2\" class=\"noline\">\n        <input class=\"publish\" type=\"submit\" name=\"save\" value=\"Save\" />\n        <input type=\"hidden\" name=\"event\" value=\"plugin_prefs.glz_custom_fields\" />\n      </td>\n    </tr>\n  </tbody>\n</table>\nEOF;\n\n  echo $out;\n}','207c1285d8e11a1a97ead38237beeb3e',1,9,3),('cnj_excerpt_logic',1,'	Caleb Jaffa','http://idiochron.org/','0.1','This plugin lets you test if there is anything in the excerpt or not.','\n	<h1>cnj_if_excerpt</h1>\n\n	<p>This plugin is part of a hack to allow Textpattern comments to be placed anywhere <p><strong><txp:cnj_if_excerpt>&#133;</txp:cnj_if_excerpt></strong><br />\n<br />\nParse the contents if the excerpt is empty.<br />\n</p><br />\n<p><strong><txp:cnj_if_not_excerpt>&#133;</txp:cnj_if_not_excerpt></strong><br />\n<br />\nParse the contents if the excerpt is not empty.<br />\n</p><br />\n<p>Personally I use this with just one form for displaying articles, if there is a list, and an excerpt display the excerpt with a link to read more, or just display the body, if it is the single article display the excerpt and the body with an id for the read more link.  The form I use is this:</p><br />\n<h3><txp:permlink><txp:title /></txp:permlink></h3><br />\n<br />\n<h4>posted <txp:posted /> category <txp:category1 /> <txp:comments_invite /></h4><br />\n<br />\n<txp:if_article_list><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;<txp:cnj_if_excerpt><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<p><txp:excerpt /></p><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<p><a href=\"<txp:permlink />#more&#8221;>Read more</a></p><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;</txp:cnj_if_excerpt><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;<txp:cnj_if_not_excerpt><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<p><txp:body /></p><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;</txp:cnj_if_not_excerpt><br />\n<br />\n</txp:if_article_list><br />\n<br />\n<txp:if_individual_article><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;<p><txp:excerpt /></p><br />\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;<p id=\"more\"><txp:body /></p><br />\n<br />\n</txp:if_individual_article></p>\n\n\n\n ','\nfunction cnj_if_excerpt($atts, $thing) {\n    global $thisarticle;\n    if(preg_match(\'/\\S/\', $thisarticle[\'excerpt\'])) {\n      return parse($thing);\n    } else {\n      return;\n    }\n}\n\nfunction cnj_if_not_excerpt($atts, $thing) {\n    global $thisarticle;\n    if(!preg_match(\'/\\S/\', $thisarticle[\'excerpt\'])) {\n      return parse($thing);\n    } else {\n      return;\n    }\n}\n','\nfunction cnj_if_excerpt($atts, $thing) {\n    global $thisarticle;\n    if(preg_match(\'/\\S/\', $thisarticle[\'excerpt\'])) {\n      return parse($thing);\n    } else {\n      return;\n    }\n}\n\nfunction cnj_if_not_excerpt($atts, $thing) {\n    global $thisarticle;\n    if(!preg_match(\'/\\S/\', $thisarticle[\'excerpt\'])) {\n      return parse($thing);\n    } else {\n      return;\n    }\n}\n','36cda465b3d3e3cd7606056f0c2ab678',0,5,0),('rss_auto_excerpt',1,'Rob Sable','http://www.wilshireone.com/','0.5','Automatic article excerpts','\n\n	<h1>Automatic article excerpts</h1>\n\n	<p>The <code>rss_auto_excerpt</code> plugin automatically displays article excerpts even if an excerpt has not been saved with an article.  If for some articles you have defined an excerpt, your own excerpt will be displayed rather than the auto-generated excerpt.  You can also override this feature so that an auto-generated excerpt is always displayed even if an excerpt has been defined.</p>\n\n	<p>There are 4 different options for auto-generating the excerpt from the article body:</p>\n\n	<ul>\n		<li><strong>By Length</strong> &#8211; specify the number of characters to display from the article body</li>\n		<li><strong>By Words</strong> &#8211; specify the number of words to display from the article body</li>\n		<li><strong>By Sentences</strong> &#8211; specify the number of sentences to display from the article body</li>\n	</ul>\n	<ul>\n		<li><strong>By Paragraphs</strong> &#8211; specify the number of paragraphs to display from the article body</li>\n	</ul>\n\n	<p>If auto-generating by length, the plugin will ensure that the excerpt does not cutoff in the middle of a word.  If based on the parameters passed into the plugin, the excerpt would not be shorter than the entire article body, the body will be shown instead.</p>\n\n	<h1>Reverse excerpts</h1>\n\n	<p>You can also use the plugin to generate a &#8220;reverse&#8221; excerpt by using the <em>skip</em> variants of the length attributes.  For example:<br />\n<pre><code>&#60;txp:if_individual_article&#62;\n  &#60;txp:rss_auto_excerpt skipparagraphs=&#34;1&#34; paragraphs=&#34;9999&#34; /&#62;\n&#60;txp:else /&#62;\n  &#60;txp:rss_auto_excerpt paragraphs=&#34;1&#34; /&#62;\n&#60;/txp:if_individual_article&#62;\n</code></pre></p>\n\n	<p>This code would display the first paragraph of your article on an article listing page, but on an individual article page, you would see all paragraphs except the first.</p>\n\n	<p>The skip tags could also be used to apply different styling to you first paragraph (i.e., larger font size) or character (i.e., drop caps).</p>\n\n	<p><strong>The plugin will also automatically close any open <span class=\"caps\">HTML</span> tags.</strong>  This will allow for proper handling of lists, bolded or italicized text and other situations.  You can also choose to strip out all <span class=\"caps\">HTML</span> tags from the excerpt.</p>\n\n	<h1>Plugin Attributes</h1>\n\n	<table style=\"color:#333;font:normal 1em verdana;width: 100%;padding: 0 0 20px;margin: 0 auto 20px;border-bottom:1px solid #666;\" id=\"list\">\n		<tr>\n			<th style=\"vertical-align:middle;white-space: nowrap;\">attribute name</th>\n			<th style=\"vertical-align:middle;white-space: nowrap;\">description</th>\n			<th style=\"vertical-align:middle;white-space: nowrap;\">default value</th>\n			<th style=\"vertical-align:middle;white-space: nowrap;\">example usage</th>\n		</tr>\n		<tr>\n			<td>length</td>\n			<td>The number of characters to display from the article body.</td>\n			<td> &nbsp;</td>\n			<td>length=&#8220;350&#8221;</td>\n		</tr>\n		<tr>\n			<td>words</td>\n			<td>The number of words to display from the article body.</td>\n			<td> &nbsp;</td>\n			<td>words=&#8220;50&#8221;</td>\n		</tr>\n		<tr>\n			<td>sentences</td>\n			<td>The number of sentences to display from the article body.</td>\n			<td> &nbsp;</td>\n			<td>sentences=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>paragraphs</td>\n			<td>The number of paragraphs to display from the article body.</td>\n			<td> &nbsp;</td>\n			<td>paragraphs=&#8220;2&#8221;</td>\n		</tr>\n		<tr>\n			<td>linktext</td>\n			<td>The link text for the permlink to the full article.</td>\n			<td>Keep Reading&#8230;</td>\n			<td>linktext=&#8220;Read More&#8221;</td>\n		</tr>\n		<tr>\n			<td>ending</td>\n			<td>The text that will be displayed at the end of the excerpt when generating the excerpt by length or words.  This is used to show that text is being truncated.</td>\n			<td>...</td>\n			<td>ending=&#8221;........&#8221;</td>\n		</tr>\n		<tr>\n			<td>linkwraptag</td>\n			<td>The <span class=\"caps\">HTML</span> tag that wraps the permlink to the full article.</td>\n			<td>p</td>\n			<td>linkwraptag=&#8220;span&#8221;</td>\n		</tr>\n		<tr>\n			<td>linkclass</td>\n			<td>The class attribute on the linkwraptag.</td>\n			<td> &nbsp;</td>\n			<td>linkclass=&#8220;morelink&#8221;</td>\n		</tr>\n		<tr>\n			<td>linklabel</td>\n			<td>A label that appears before the permlink to the full article.  It will appear outside the link tag.</td>\n			<td> &nbsp;</td>\n			<td>linklabel=&#8221;- &#8220;</td>\n		</tr>\n		<tr>\n			<td>wrapreadmore</td>\n			<td>Determines whether the permlink to the article will be wrapped in the last closing tag of the excerpt or placed outside.</td>\n			<td>0</td>\n			<td>wrapreadmore=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>excerptwraptag</td>\n			<td>The <span class=\"caps\">HTML</span> tag that wraps the excerpt of the full article.</td>\n			<td>p</td>\n			<td>excerptwraptag=&#8220;span&#8221;</td>\n		</tr>\n		<tr>\n			<td>showlinkwithbody</td>\n			<td>Determines whether the permlink to the article will be shown when the article body is displayed because the generated excerpt is not shorter than the article body.</td>\n			<td>0</td>\n			<td>showlinkwithbody=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>showlinkwithexcerpt</td>\n			<td>Determines whether the permlink to the article will be shown when the automatic excerpt is displayed.</td>\n			<td>1</td>\n			<td>showlinkwithexcerpt=&#8220;0&#8221;</td>\n		</tr>\n		<tr>\n			<td>overrideexcerpt</td>\n			<td>Displays an automatic excerpt even if the article has an excerpt defined.</td>\n			<td>0</td>\n			<td>overrideexcerpt=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>striptags</td>\n			<td>Strips <span class=\"caps\">HTML</span> tags from the automatic excerpt that is displayed.</td>\n			<td>0</td>\n			<td>striptags=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>stripbreakstabs</td>\n			<td>Strips line breaks and tabs from the automatic excerpt that is displayed.</td>\n			<td>0</td>\n			<td>stripbreakstabs=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>skiplength</td>\n			<td>The number of characters to skip at the beginning of the display from the article body.</td>\n			<td>0</td>\n			<td>skiplength=&#8220;50&#8221;</td>\n		</tr>\n		<tr>\n			<td>skipwords</td>\n			<td>The number of words to skip at the beginning of the display from the article body.</td>\n			<td>0</td>\n			<td>skipwords=&#8220;2&#8221;</td>\n		</tr>\n		<tr>\n			<td>skipsentences</td>\n			<td>The number of sentences to skip at the beginning of the display from the article body.</td>\n			<td>0</td>\n			<td>skipsentences=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>skipparagraphs</td>\n			<td>The number of paragraphs to skip at the beginning of the display from the article body.</td>\n			<td>0</td>\n			<td>skipparagraphs=&#8220;1&#8221;</td>\n		</tr>\n		<tr>\n			<td>excerpt</td>\n			<td>The field name to use for the article excerpt.</td>\n			<td>excerpt</td>\n			<td>excerpt=&#8220;custom1&#8221;</td>\n		</tr>\n		<tr>\n			<td>body</td>\n			<td>The field name to use for the article body.</td>\n			<td>body</td>\n			<td>body=&#8220;custom2&#8221;</td>\n		</tr>\n	</table>','\n	function rss_auto_excerpt($atts) {\n		global $thisarticle;\n\n		extract(lAtts(array(\n			\'linkwraptag\' => \'p\',\n			\'linkclass\' => \'\',\n			\'linklabel\' => \'\',\n			\'linktext\' => \'Keep Reading...\',\n			\'excerptwraptag\' => \'\',\n			\'length\' => 0,\n			\'words\' => 0,\n			\'sentences\' => 0,\n			\'paragraphs\' => 0,\n			\'skiplength\' => 0,\n			\'skipwords\' => 0,\n			\'skipsentences\' => 0,\n			\'skipparagraphs\' => 0,\n			\'ending\' => \'...\',\n			\'showlinkwithbody\' => 0,\n			\'showlinkwithexcerpt\' => 1,\n			\'overrideexcerpt\' => 0,\n			\'striptags\' => 0,\n			\'stripbreakstabs\' => 0,\n			\'wrapreadmore\' => 0,\n			\'excerpt\' => \'excerpt\',\n			\'body\' => \'body\',\n		),$atts));\n\n		$excerpt = trim($thisarticle[$excerpt]);\n		$body = trim($thisarticle[$body]);\n\n		// if the article has an excerpt, show it\n		if ($excerpt != \'\' && !$overrideexcerpt) {\n			$autoex = ($excerptwraptag) ? tag(parse($excerpt),$excerptwraptag).n : parse($excerpt).n;\n			$autoex.= ($showlinkwithexcerpt) ? doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \"\";\n			return $autoex;\n		}\n\n		$body = ($striptags) ? strip_tags($body) : $body;\n\n		$body = ($stripbreakstabs) ? ereg_replace(\"\\n|\\r|\\r\\n|\\n\\r|\\t\", \" \", preg_replace(\'/\\s\\s+/\', \' \', trim($body))) : $body;\n		$charcount = strlen($body);\n		$wordcount = count(explode(\" \", $body));\n		$sencount = count(explode(\".\", $body));\n		$pghcount = count(explode(\"</p>\", $body));\n\n		if (!$length && !$words && !$sentences && !$paragraphs) $length = 150;\n\n		$doex = 0;\n		$doex = ($length) ? ($length < $charcount) ? 1 : 0 : $doex;\n		$doex = ($words) ? ($words < $wordcount) ? 1 : 0 : $doex;\n		$doex = ($sentences) ? ($sentences < $sencount) ? 1 : 0 : $doex;\n		$doex = ($paragraphs) ? ($paragraphs < $pghcount) ? 1 : 0 : $doex;\n\n		if ($doex) {\n			if ($length) {\n				$exa = explode(\" \", substr($body, $skiplength, $length));\n				if (count($exa) > 1) array_pop($exa);\n				$ex = implode(\" \",$exa);\n			} else if ($words) {\n				$allwords = explode(\" \", $body);\n				$awa = array_slice($allwords, $skipwords, $words);\n				$ex = implode(\" \",$awa);\n			} else if ($sentences) {\n				$allsens = explode(\".\", $body);\n				$asa = array_slice($allsens, $skipsentences, $sentences);\n				$ex = implode(\".\",$asa).\".\";\n				$ending = \"\";\n			} else if ($paragraphs) {\n				$allpghs = explode(\"</p>\", $body);\n				$awp = array_slice($allpghs, $skipparagraphs, $paragraphs);\n				$ex = implode(\"</p>\",$awp);\n				$ending = \"\";\n			}\n			$ex.= $ending.rssAutoCloseTags($ex);\n\n			// find the last closing tag\n			preg_match_all(\"/<\\/(([A-Z]|[a-z]).*)(( )|(>))/isU\",$ex,$closetags);\n			$lasttag = end($closetags[0]);\n\n			// add the read more text either inside the last closing tag or outside\n			if ($wrapreadmore && $lasttag) {\n				$exrm = ($showlinkwithexcerpt) ? doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \'\';\n				$ex = substr($ex, 0, -(strlen($lasttag))) . $exrm . $lasttag;\n			} else {\n				$ex.= ($showlinkwithexcerpt) ? n . doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \'\';\n			}\n\n		} else {\n			$ex = parse($body);\n			$ex.= ($showlinkwithbody) ? doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \'\';\n		}\n\n		return $ex;\n	}\n\n// ----------------------------------------------------\n\n	function rssAutoCloseTags($string) {\n		// automatically close HTML-Tags\n		// (usefull e.g. if you want to extract part of a blog entry or news as preview/teaser)\n		// coded by Constantin Gross <connum at googlemail dot com> / 3rd of June, 2006\n		// feel free to leave comments or to improve this function!\n		// Updates by Rob Sable <www.wilshireone.com> / 20th of August, 2006\n\n		$donotclose=array(\'br\',\'img\',\'input\'); //Tags that are not to be closed\n\n		//prepare vars and arrays\n		$tagstoclose=\'\';\n		$tags=array();\n\n		//put all opened tags into an array\n		preg_match_all(\"/<(([A-Z]|[a-z]).*)(( )|(>))/isU\",$string,$result);\n		$openedtags=$result[1];\n		$openedtags=array_reverse($openedtags); //this is just done so that the order of the closed tags in the end will be better\n\n		//put all closed tags into an array\n		preg_match_all(\"/<\\/(([A-Z]|[a-z]).*)(( )|(>))/isU\",$string,$result2);\n		$closedtags=$result2[1];\n\n		//look up which tags still have to be closed and put them in an array\n		for ($i=0;$i<count($openedtags);$i++) {\n			 if (in_array($openedtags[$i],$closedtags)) { unset($closedtags[array_search($openedtags[$i],$closedtags)]); }\n					 else array_push($tags, $openedtags[$i]);\n		}\n		//$tags=array_reverse($tags); //now this reversion is done again for a better order of close-tags\n\n		//prepare the close-tags for output\n		for($x=0;$x<count($tags);$x++) {\n		$add=strtolower(trim($tags[$x]));\n		if(!in_array($add,$donotclose)) $tagstoclose.=\'</\'.$add.\'>\';\n		}\n\n		//and finally\n		return $tagstoclose;\n	}\n','\n	function rss_auto_excerpt($atts) {\n		global $thisarticle;\n\n		extract(lAtts(array(\n			\'linkwraptag\' => \'p\',\n			\'linkclass\' => \'\',\n			\'linklabel\' => \'\',\n			\'linktext\' => \'Keep Reading...\',\n			\'excerptwraptag\' => \'\',\n			\'length\' => 0,\n			\'words\' => 0,\n			\'sentences\' => 0,\n			\'paragraphs\' => 0,\n			\'skiplength\' => 0,\n			\'skipwords\' => 0,\n			\'skipsentences\' => 0,\n			\'skipparagraphs\' => 0,\n			\'ending\' => \'...\',\n			\'showlinkwithbody\' => 0,\n			\'showlinkwithexcerpt\' => 1,\n			\'overrideexcerpt\' => 0,\n			\'striptags\' => 0,\n			\'stripbreakstabs\' => 0,\n			\'wrapreadmore\' => 0,\n			\'excerpt\' => \'excerpt\',\n			\'body\' => \'body\',\n		),$atts));\n\n		$excerpt = trim($thisarticle[$excerpt]);\n		$body = trim($thisarticle[$body]);\n\n		// if the article has an excerpt, show it\n		if ($excerpt != \'\' && !$overrideexcerpt) {\n			$autoex = ($excerptwraptag) ? tag(parse($excerpt),$excerptwraptag).n : parse($excerpt).n;\n			$autoex.= ($showlinkwithexcerpt) ? doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \"\";\n			return $autoex;\n		}\n\n		$body = ($striptags) ? strip_tags($body) : $body;\n\n		$body = ($stripbreakstabs) ? ereg_replace(\"\\n|\\r|\\r\\n|\\n\\r|\\t\", \" \", preg_replace(\'/\\s\\s+/\', \' \', trim($body))) : $body;\n		$charcount = strlen($body);\n		$wordcount = count(explode(\" \", $body));\n		$sencount = count(explode(\".\", $body));\n		$pghcount = count(explode(\"</p>\", $body));\n\n		if (!$length && !$words && !$sentences && !$paragraphs) $length = 150;\n\n		$doex = 0;\n		$doex = ($length) ? ($length < $charcount) ? 1 : 0 : $doex;\n		$doex = ($words) ? ($words < $wordcount) ? 1 : 0 : $doex;\n		$doex = ($sentences) ? ($sentences < $sencount) ? 1 : 0 : $doex;\n		$doex = ($paragraphs) ? ($paragraphs < $pghcount) ? 1 : 0 : $doex;\n\n		if ($doex) {\n			if ($length) {\n				$exa = explode(\" \", substr($body, $skiplength, $length));\n				if (count($exa) > 1) array_pop($exa);\n				$ex = implode(\" \",$exa);\n			} else if ($words) {\n				$allwords = explode(\" \", $body);\n				$awa = array_slice($allwords, $skipwords, $words);\n				$ex = implode(\" \",$awa);\n			} else if ($sentences) {\n				$allsens = explode(\".\", $body);\n				$asa = array_slice($allsens, $skipsentences, $sentences);\n				$ex = implode(\".\",$asa).\".\";\n				$ending = \"\";\n			} else if ($paragraphs) {\n				$allpghs = explode(\"</p>\", $body);\n				$awp = array_slice($allpghs, $skipparagraphs, $paragraphs);\n				$ex = implode(\"</p>\",$awp);\n				$ending = \"\";\n			}\n			$ex.= $ending.rssAutoCloseTags($ex);\n\n			// find the last closing tag\n			preg_match_all(\"/<\\/(([A-Z]|[a-z]).*)(( )|(>))/isU\",$ex,$closetags);\n			$lasttag = end($closetags[0]);\n\n			// add the read more text either inside the last closing tag or outside\n			if ($wrapreadmore && $lasttag) {\n				$exrm = ($showlinkwithexcerpt) ? doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \'\';\n				$ex = substr($ex, 0, -(strlen($lasttag))) . $exrm . $lasttag;\n			} else {\n				$ex.= ($showlinkwithexcerpt) ? n . doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \'\';\n			}\n\n		} else {\n			$ex = parse($body);\n			$ex.= ($showlinkwithbody) ? doTag($linklabel . permlink(array(), $linktext),$linkwraptag,$linkclass) : \'\';\n		}\n\n		return $ex;\n	}\n\n// ----------------------------------------------------\n\n	function rssAutoCloseTags($string) {\n		// automatically close HTML-Tags\n		// (usefull e.g. if you want to extract part of a blog entry or news as preview/teaser)\n		// coded by Constantin Gross <connum at googlemail dot com> / 3rd of June, 2006\n		// feel free to leave comments or to improve this function!\n		// Updates by Rob Sable <www.wilshireone.com> / 20th of August, 2006\n\n		$donotclose=array(\'br\',\'img\',\'input\'); //Tags that are not to be closed\n\n		//prepare vars and arrays\n		$tagstoclose=\'\';\n		$tags=array();\n\n		//put all opened tags into an array\n		preg_match_all(\"/<(([A-Z]|[a-z]).*)(( )|(>))/isU\",$string,$result);\n		$openedtags=$result[1];\n		$openedtags=array_reverse($openedtags); //this is just done so that the order of the closed tags in the end will be better\n\n		//put all closed tags into an array\n		preg_match_all(\"/<\\/(([A-Z]|[a-z]).*)(( )|(>))/isU\",$string,$result2);\n		$closedtags=$result2[1];\n\n		//look up which tags still have to be closed and put them in an array\n		for ($i=0;$i<count($openedtags);$i++) {\n			 if (in_array($openedtags[$i],$closedtags)) { unset($closedtags[array_search($openedtags[$i],$closedtags)]); }\n					 else array_push($tags, $openedtags[$i]);\n		}\n		//$tags=array_reverse($tags); //now this reversion is done again for a better order of close-tags\n\n		//prepare the close-tags for output\n		for($x=0;$x<count($tags);$x++) {\n		$add=strtolower(trim($tags[$x]));\n		if(!in_array($add,$donotclose)) $tagstoclose.=\'</\'.$add.\'>\';\n		}\n\n		//and finally\n		return $tagstoclose;\n	}\n','73ef40a4bc40275c2f3b1a49e160b0f4',0,5,0),('bot_image_upload',1,'redbot','http://www.redbot.it/txp','0.6.1','Upload, edit, sort and show images within the \'write\' tab','<h2>bot | image upload</h2>\n\n<p>This plugin allows to insert, upload, sort, show and edit  images within the &#8216;write&#8217; tab.</p>\n<h3>Features:</h3>\n<ul>\n  <li>Multiple fields (&quot;article image&quot; or  any other custom field) can be set for the plugin to operate.</li>\n  <li>A field can be set to accept single or multiple  images</li>\n  <li>Image thumbnails associated with an article are shown in the \'write\' tab  </li>\n  <li>drag\'n\'drop support for easy images sorting in the \'write\' tab\'</li>\n</ul>\n<h3>How it works </h3>\n<p>Multiple fields can be set. For example you may want to set the &quot;article image&quot; field to accept only one image,  custom field 2 to accept a list of them for a gallery,  custom field 3 for another gallery  and so on </p>\n<p> The plugin does not alter texpattern natural behavieur, it just   operates at a  visual level hiding the  field and replacing it with an interface. Under the skin, images are still stored normally as  comma separated values.</p>\n<p> If you are associating a lot of images with an article I suggest to use my other plugin \"<a href=\"http://forum.textpattern.com/viewtopic.php?id=32175\">bot_wtc</a>\"  to move the field in the central colum for a nicier look</p>\n<h3>Installation</h3>\n<p>Just install the plugin the normal way. If you want to sort images (optional) you must upload the jquery ui script which comes with the plugin. Default location is in \'textpattern\' directory. If you choose another you must change the path in the plugins preferences (bot_iu_ui_path).</p>\n<h3>Other plugins compatibility </h3>\n<p> If you are using another plugin which already loads <strong>the entire </strong>jQuery ui script (such as msd_admin_datepicker) you don\'t want to load it again causing issues so you must set bot_iu_ui_path to \'\'. Mind that the other plugin must load <strong>the complete </strong>ui script (including sortables), if it is another custom ui which does not include sortables you still have to use the script provided with the download and set bot_iu_ui_path accordingly. </p>\n<h3>Configuration - customization</h3>\n\n<p>If you want to change some default settings configure the plugin directly in the plugins code. Go to plugins &gt; edit and  search for &#8216;Global preferences - Configuration&#8217; in the first lines. <br />\nYou\'ll see something like this:\n</p>\n		<p><code>\'bot_iu_fields\' =&gt; \'#article-image // fields to be used<br />\n  \'bot_iu_mono_list\' =&gt; \'\', // filelds with single image<br />\n  \'bot_choose_image_text\' =&gt; gTxt(\'Choose image\'), // text for &quot;Choose images&quot; link and button<br />\n  \'bot_image_delete_text\' =&gt; gTxt(\'Delete image\'), // text and title for &quot;delete image&quot; button<br />\n  \'bot_image_edit_text\' =&gt; gTxt(\'Edit image\'), // text and title for &quot;edit image&quot; button&quot;<br />\n  \'bot_add_image_text\' =&gt; gTxt(\'Add\'), // text for &quot;add image&quot; checkbox<br />\n  \'bot_iu_save_text\' =&gt; gTxt(\'save\'), // text for &quot;Save&quot; button&quot;<br />\n  \'bot_iu_cancel_text\' =&gt; gTxt(\'cancel\'), // text for &quot;Cancel&quot; button&quot;<br />\n\'bot_iu_row_bg\' =&gt; \'#eaeaea\', // selected row background<br />\n		\'bot_iu_ui_path\' =&gt; \'jquery-ui-1.8.9.custom.min.js\', // path to the jQuery ui script. Defaults to the \'textpattern\' directory</code></p>\n		<p>To configure change the part that comes after the &quot;=&gt;&quot; and its enclosed in single quotes. Read comments for help.</p>\n		<p>The most important configuration options are the first two: </p>\n		<ol>\n		  <li>&quot;bot_iu_fields&quot; determines  the fields which will be used (can be &quot;article image&quot; or  any other custom field)</li>\n		  <li>\'bot_iu_mono_list\' sets the fields which will accept only a single image</li>\n</ol>\n		<p>Each of them takes a comma separated list of values which <strong>must be</strong> in this form:</p>\n		<p><code>#article-image </code>for article image and <br />\n	    <code>#custom-n for custom fields where n is the custom field id </code> </p>\n		<p>For an example I could configure them this way:</p>\n		<p><code>\'bot_iu_fields\' =&gt; \'#article-image, #custom-3, #custom-2\' // fields to be used<br />\n  \'bot_iu_mono_list\' =&gt; \'#article-image, #custom-3,\', // filelds with single image </code></p>\n<p>This plugin can be quite easily adapted to your needs, from text to aspect. If you want to modify its look edit the css in the function \'bot_image_css\'. For more complex mods you will save some time if you have a look at the underlying html structure first.</p><p>Keep in mind that the iframe content style cannot be addressed throught this css: you\'ll have to add or change some js lines.</p>','//<?\r\n\r\n	if(@txpinterface == \'admin\') {\r\n		register_callback(\'bot_image_upload\',\'article\');\r\n		register_callback(\'bot_image_css\',\'admin_side\',\'head_end\');\r\n 		bot_image_img();\r\n	}\r\n\r\n/*******************************************************************************\r\n	Global preferences - Configuration. Read comments and modify to your needs.\r\n*******************************************************************************/\r\n\r\n	function bot_iu_prefs() {\r\n		return\r\n			array(\r\n				\'bot_iu_fields\' => \'#article-image\', // fields to be used (comma separated | use #custom-n for cfs)\r\n				\'bot_iu_mono_list\' => \'\', // filelds with single image (comma separated | use #custom-n for cfs)\r\n				\'bot_choose_image_text\' => gTxt(\'Choose image\'), // text for \"Choose images\" link and button\r\n				\'bot_image_delete_text\' => gTxt(\'Delete image\'), // text and title for \"delete image\" button\r\n				\'bot_image_edit_text\' => gTxt(\'Edit image\'), // text and title for \"edit image\" button\"\r\n				\'bot_add_image_text\' => gTxt(\'Add\'), // text for \"add image\" checkbox\r\n				\'bot_iu_save_text\' => gTxt(\'save\'), // text for \"Save\" button\"\r\n				\'bot_iu_cancel_text\' => gTxt(\'cancel\'), // text for \"Cancel\" button\"\r\n				\'bot_iu_row_bg\' => \'#eaeaea\', // selected row background\r\n				\'bot_iu_ui_path\' => \'jquery-ui-1.8.9.custom.min.js\', // path to the jQuery ui script. Defaults to \'textpattern\' directory. Set to \'\' if ui already loaded\r\n			);\r\n	}\r\n\r\n/**\r\n	CSS for the image upload. You are free to modify these\r\n	to match your own backend theme.\r\n*/\r\n\r\n	function bot_image_css() {\r\n\r\n		global $event;\r\n		if($event != \'article\') { // Outputs css only in \'write\' tab.\r\n			return;\r\n		}\r\n\r\n		echo \'<style type=\"text/css\">\r\n				.bot_image_delete {\r\n					background: url(\"?bot_image_img=delete\") top center no-repeat;\r\n					display:inline-block;\r\n					text-indent: -99999px;\r\n					width:15px;\r\n					height:20px;\r\n				}\r\n				.bot_image_edit {\r\n					background:url(\"?bot_image_img=edit\") top center no-repeat;\r\n					display:inline-block;\r\n					text-indent:-99999px;\r\n					width:15px;\r\n					height:20px;\r\n					margin-right: 5px;\r\n				}\r\n				#bot_iu_loading {\r\n					background:#000 url(\"?bot_image_img=bot_iu_loading\") center center no-repeat;\r\n					text-indent:-99999px;\r\n					width:50px;\r\n					height:50px;\r\n					padding:10px;\r\n					position:fixed;\r\n					left:50%;\r\n					margin-left:-30px;\r\n					top:50%;\r\n					margin-top:-30px;\r\n					z-index:9999;\r\n					-moz-border-radius:10px;\r\n					-webkit-border-radius:10px;\r\n					border-radius: 10px;\r\n				}\r\n				#bot_iu_fade {\r\n					display: none;\r\n					background: #000;\r\n					position: fixed; left: 0; top: 0;\r\n					width: 100%; height: 100%;\r\n					opacity: .80;\r\n					z-index: 999;\r\n				}\r\n				#bot_iu_iframe {\r\n					width:800px;\r\n				}\r\n				#bot_iu_iframe_container {\r\n				    /* height and margin-top are set by js */\r\n				    display:none;\r\n				    position:fixed;\r\n				    left:50%;\r\n				    z-index: 99999;\r\n					overflow: hidden;\r\n					background: #f4f4f4;\r\n					width:800px;\r\n					padding:0 20px;\r\n					margin-left: -400px;\r\n					text-align:right;\r\n					-moz-border-radius:5px;\r\n					-webkit-border-radius:10px;\r\n					border-radius: 10px;\r\n					-moz-box-shadow: 0 0 20px #000;\r\n					-webkit-box-shadow: 0 0 20px #000;\r\n					box-shadow: 0 0 20px #000;\r\n				}\r\n				#bot_iu_save,\r\n				#bot_iu_cancel {\r\n					background:#666;\r\n					color:#fff;\r\n					font-weight:bold;\r\n					padding:5px 10px;\r\n					margin-left:5px;\r\n					display:inline-block;\r\n					cursor:pointer;\r\n					-moz-border-radius:5px;\r\n					-webkit-border-radius:5px;\r\n					border-radius:5px;\r\n				}\r\n				#bot_iu_save:hover,\r\n				#bot_iu_cancel:hover {\r\n					background:#333;\r\n					text-decoration:none;\r\n				}\r\n				.bot_iu_ul_container {\r\n					margin:0;\r\n				}\r\n				.bot_iu_image_container {\r\n					display:inline-block;\r\n					border:solid #eaeaea 1px;\r\n					background: #fff;\r\n					padding:10px 10px 0;\r\n					-moz-box-shadow:2px 2px 5px #ccc;\r\n					-webkit-box-shadow:2px 2px 5px #ccc;\r\n					box-shadow:2px 2px 5px #ccc;\r\n				}\r\n				.bot_iu_image_container span {\r\n					display:block;\r\n					overflow:hidden;\r\n					padding-top:5px;\r\n				}\r\n				.bot_add_image {\r\n					display:block;\r\n				}\r\n			</style>\r\n			\r\n			<!--[if lte IE 7]>\r\n				<style>\r\n					/*-- styling for fucking ie7 and below --*/\r\n					.bot_iu_image_container {\r\n						display:inline;\r\n					}\r\n					.bot_image_delete,\r\n					.bot_image_edit {\r\n						float:left;\r\n					}\r\n				</style>\r\n			<![endif]-->\r\n			\r\n			<!--[if lte IE 6]>\r\n				<style>\r\n					/*-- minimal styling for fucking ie6 and below --*/\r\n					#bot_iu_fade,\r\n					#bot_iu_loading,\r\n					#bot_iu_iframe_container {\r\n						position: absolute;\r\n					}\r\n					#bot_iu_iframe_container {\r\n						border: solid #ccc thick;\r\n					}\r\n				</style>\r\n			<![endif]-->\';\r\n	}\r\n\r\n/**\r\n	Generates and stores the images required by the design.\r\n	Image URI is: http://example.com/textpattern/?bot_image_img=delete|edit|file\r\n*/\r\n\r\n	function bot_image_img() {\r\n\r\n 	global $event;\r\n		if($event != \'article\') { // Generates images only in \'write\' tab.\r\n			return;\r\n		}\r\n		$image = gps(\'bot_image_img\');\r\n\r\n		if(!$image)\r\n			return;\r\n\r\n		switch($image) {\r\n			case \'delete\':\r\n				$file = \'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABEElEQVR42mL4//8/Ayn4zJkzXMh8gABiYkACZ8+elQdibQYcACqXCqTtYGIAAcQIMgWmGUg9gIrrGBsbX8Wi+QqUuxKIG4FqrgMEENgANM0M6IagaYaBAiCeDBBAMAM4gJyvQMyEbgiURtf8F4g5gRb8BgggZC+ADPkCxMwM+AFIMw9Q8w8QByCA4DZCBXigCojSDAIAAYTiZCRD/mHR/A9dMwgABBATFoXKOMSZoHIoACCAmPBEFTZwBT2dAAQQEwHNf7F4B8UQgABiIqAZFB7cWAIWbghAAMFcIIYrtPHEDlgPQAAxQUN/P5BywhXaWAxxguphAAgg9JzmCMQceHIiB0gNshhAAMFTIrkAIMAA7k7JUu0YckQAAAAASUVORK5CYII=\';\r\n				break;\r\n			case \'edit\':\r\n				$file = \'iVBORw0KGgoAAAANSUhEUgAAABMAAAAUCAMAAABYi/ZGAAAABGdBTUEAAK/INwWK6QAAABl0RVh0 U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACiUExURf7+/v39/bOzs+rq6uHh4dXV1c3N zb6+vqioqLKysq6urqmpqfb29tDQ0O7u7vPz8+3t7d7e3q2trc/Pz7CwsLm5udPT09HR0d3d3fHx 8fT09MXFxaqqqsDAwNra2tTU1Ovr67GxsfLy8qysrNfX17i4uLe3t8HBwaenp/r6+uzs7ODg4N/f 3+/v78nJyenp6bu7u7+/v8zMzNnZ2dLS0v///181u00AAAA2dFJOU/////////////////////// ////////////////////////////////////////////////AKGPTjEAAADaSURBVHjaYjDFBAAB xIDEZuRl5wPRAAGEJMYgziVixANkAAQQkpi4mqoGkzSQARBACDE2WX0TIQ4mIAsggOBiwoZaPLrS 3CxAJkAAwcSE2QX4FYxFJUB8gACCirGx8ykxyzMJgrkAAQQR41UXkGRm5RRkBPMAAggsJmYgKcXM qigBETIFCCCwmLKKnhSriA5UyBQggMBiHKIyLFzaMCFTgAACi3ELMXGyIFwKEEBgFpsYvxyShwAC CGK5Jkq4AAQQA5awAgggbGIAAYRNDCCAsIkBBBA2MYAAAwCXW0H+487c7QAAAABJRU5ErkJggg==\';\r\n				break;\r\n			default:\r\n				$file = \'R0lGODlhHwAfAPUAAAAAAP///xYWFiwsLEJCQlBQUFxcXCIiIkZGRmRkZBoaGiYmJlRUVF5eXk5OTjIyMggICFZWVioqKhgYGMjIyNjY2K6urjo6Oo6OjmxsbKioqAQEBJaWlri4uDg4OAYGBra2tszMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAHwAfAAAG/0CAcEgUDAgFA4BiwSQexKh0eEAkrldAZbvlOD5TqYKALWu5XIwnPFwwymY0GsRgAxrwuJwbCi8aAHlYZ3sVdwtRCm8JgVgODwoQAAIXGRpojQwKRGSDCRESYRsGHYZlBFR5AJt2a3kHQlZlERN2QxMRcAiTeaG2QxJ5RnAOv1EOcEdwUMZDD3BIcKzNq3BJcJLUABBwStrNBtjf3GUGBdLfCtadWMzUz6cDxN/IZQMCvdTBcAIAsli0jOHSJeSAqmlhNr0awo7RJ19TJORqdAXVEEVZyjyKtE3Bg3oZE2iK8oeiKkFZGiCaggelSTiA2LhxiZLBSjZjBL2siNBOFQ84LxHA+mYEiRJzBO7ZCQIAIfkECQoAAAAsAAAAAB8AHwAABv9AgHBIFAwIBQPAUCAMBMSodHhAJK5XAPaKOEynCsIWqx0nCIrvcMEwZ90JxkINaMATZXfju9jf82YAIQxRCm14Ww4PChAAEAoPDlsAFRUgHkRiZAkREmoSEXiVlRgfQgeBaXRpo6MOQlZbERN0Qx4drRUcAAJmnrVDBrkVDwNjr8BDGxq5Z2MPyUQZuRgFY6rRABe5FgZjjdm8uRTh2d5b4NkQY0zX5QpjTc/lD2NOx+WSW0++2RJmUGJhmZVsQqgtCE6lqpXGjBchmt50+hQKEAEiht5gUcTIESR9GhlgE9IH0BiTkxrMmWIHDkose9SwcQlHDsOIk9ygiVbl5JgMLuV4HUmypMkTOkEAACH5BAkKAAAALAAAAAAfAB8AAAb/QIBwSBQMCAUDwFAgDATEqHR4QCSuVwD2ijhMpwrCFqsdJwiK73DBMGfdCcZCDWjAE2V347vY3/NmdXNECm14Ww4PChAAEAoPDltlDGlDYmQJERJqEhGHWARUgZVqaWZeAFZbERN0QxOeWwgAAmabrkMSZkZjDrhRkVtHYw+/RA9jSGOkxgpjSWOMxkIQY0rT0wbR2LQV3t4UBcvcF9/eFpdYxdgZ5hUYA73YGxruCbVjt78G7hXFqlhY/fLQwR0HIQdGuUrTz5eQdIc0cfIEwByGD0MKvcGSaFGjR8GyeAPhIUofQGNQSgrB4IsdOCqx7FHDBiYcOQshYjKDxliVDpRjunCjdSTJkiZP6AQBACH5BAkKAAAALAAAAAAfAB8AAAb/QIBwSBQMCAUDwFAgDATEqHR4QCSuVwD2ijhMpwrCFqsdJwiK73DBMGfdCcZCDWjAE2V347vY3/NmdXNECm14Ww4PChAAEAoPDltlDGlDYmQJERJqEhGHWARUgZVqaWZeAFZbERN0QxOeWwgAAmabrkMSZkZjDrhRkVtHYw+/RA9jSGOkxgpjSWOMxkIQY0rT0wbR2I3WBcvczltNxNzIW0693MFYT7bTumNQqlisv7BjswAHo64egFdQAbj0RtOXDQY6VAAUakihN1gSLaJ1IYOGChgXXqEUpQ9ASRlDYhT0xQ4cACJDhqDD5mRKjCAYuArjBmVKDP9+VRljMyMHDwcfuBlBooSCBQwJiqkJAgAh+QQJCgAAACwAAAAAHwAfAAAG/0CAcEgUDAgFA8BQIAwExKh0eEAkrlcA9oo4TKcKwharHScIiu9wwTBn3QnGQg1owBNld+O72N/zZnVzRApteFsODwoQABAKDw5bZQxpQ2JkCRESahIRh1gEVIGVamlmXgBWWxETdEMTnlsIAAJmm65DEmZGYw64UZFbR2MPv0QPY0hjpMYKY0ljjMZCEGNK09MG0diN1gXL3M5bTcTcyFtOvdzBWE+207pjUKpYrL+wY7MAB4EerqZjUAG4lKVCBwMbvnT6dCXUkEIFK0jUkOECFEeQJF2hFKUPAIkgQwIaI+hLiJAoR27Zo4YBCJQgVW4cpMYDBpgVZKL59cEBhw+U+QROQ4bBAoUlTZ7QCQIAIfkECQoAAAAsAAAAAB8AHwAABv9AgHBIFAwIBQPAUCAMBMSodHhAJK5XAPaKOEynCsIWqx0nCIrvcMEwZ90JxkINaMATZXfju9jf82Z1c0QKbXhbDg8KEAAQCg8OW2UMaUNiZAkREmoSEYdYBFSBlWppZl4AVlsRE3RDE55bCAACZpuuQxJmRmMOuFGRW0djD79ED2NIY6TGCmNJY4zGQhBjStPTFBXb21DY1VsGFtzbF9gAzlsFGOQVGefIW2LtGhvYwVgDD+0V17+6Y6BwaNfBwy9YY2YBcMAPnStTY1B9YMdNiyZOngCFGuIBxDZAiRY1eoTvE6UoDEIAGrNSUoNBUuzAaYlljxo2M+HIeXiJpRsRNMaq+JSFCpsRJEqYOPH2JQgAIfkECQoAAAAsAAAAAB8AHwAABv9AgHBIFAwIBQPAUCAMBMSodHhAJK5XAPaKOEynCsIWqx0nCIrvcMEwZ90JxkINaMATZXfjywjlzX9jdXNEHiAVFX8ODwoQABAKDw5bZQxpQh8YiIhaERJqEhF4WwRDDpubAJdqaWZeAByoFR0edEMTolsIAA+yFUq2QxJmAgmyGhvBRJNbA5qoGcpED2MEFrIX0kMKYwUUslDaj2PA4soGY47iEOQFY6vS3FtNYw/m1KQDYw7mzFhPZj5JGzYGipUtESYowzVmF4ADgOCBCZTgFQAxZBJ4AiXqT6ltbUZhWdToUSR/Ii1FWbDnDkUyDQhJsQPn5ZU9atjUhCPHVhgTNy/RSKsiqKFFbUaQKGHiJNyXIAAh+QQJCgAAACwAAAAAHwAfAAAG/0CAcEh8JDAWCsBQIAwExKhU+HFwKlgsIMHlIg7TqQeTLW+7XYIiPGSAymY0mrFgA0LwuLzbCC/6eVlnewkADXVECgxcAGUaGRdQEAoPDmhnDGtDBJcVHQYbYRIRhWgEQwd7AB52AGt7YAAIchETrUITpGgIAAJ7ErdDEnsCA3IOwUSWaAOcaA/JQ0amBXKa0QpyBQZyENFCEHIG39HcaN7f4WhM1uTZaE1y0N/TacZoyN/LXU+/0cNyoMxCUytYLjm8AKSS46rVKzmxADhjlCACMFGkBiU4NUQRxS4OHijwNqnSJS6ZovzRyJAQo0NhGrgs5bIPmwWLCLHsQsfhxBWTe9QkOzCwC8sv5Ho127akyRM7QQAAOwAAAAAAAAAAAA==\';\r\n		}\r\n\r\n		ob_start();\r\n		ob_end_clean();\r\n		header(\'Content-type: image/gif\');\r\n		echo base64_decode($file);\r\n		exit();\r\n	}\r\n\r\n\r\n    function bot_image_generate_thumbnail()\r\n    {\r\n		global $prefs, $step;\r\n		extract(bot_iu_prefs());\r\n		$image_path = hu.$prefs[\'img_dir\'];\r\n		$article_id = gps(\'ID\'); // Fetch article id from $_GET, if any, or sets it to \'\'\r\n    	$fields_array = explode(\",\", $bot_iu_fields); // tranforms in array\r\n		for ($i =0; $i < count($fields_array); $i++) { // changes array values to be used with urls and db\r\n			$current_field = trim($fields_array[$i]);  \r\n			$current_field = ($current_field == \'#article-image\') ? \'Image\': str_replace(\'#custom-\', \'custom_\', $current_field);\r\n			$fields_array[$i] = $current_field; // reinserts modified value\r\n		}\r\n\r\n        if ($step == \'edit\' && $article_id) { // when opening an already existant article\r\n			$fields_string = implode(\',\', $fields_array);\r\n            $values = safe_row($fields_string, \'textpattern\', \'ID = \'. $article_id);\r\n    	}\r\n\r\n    	elseif($step == \'create\' || $step == \'edit\') { // when hitting \'save\'\r\n			for ($i =0; $i < count($fields_array); $i++) { // fetch all image ids and put in array \'values\'\r\n				$current = $fields_array[$i];  \r\n				$values[] = gps($current_field);\r\n			}\r\n    	}\r\n		\r\n		// creates a numerical array of all images for current article\r\n		$values = array_filter(array_values($values)); // convert to numerical array and remove empty values		\r\n		$values = explode(\',\', implode(\',\', $values)); // only one value per array key\r\n		// Sanitizes values\r\n      	foreach($values as $value) {\r\n		    if(is_numeric($value)) {\r\n			    $ids[] = \"\'\".doSlash($value).\"\'\";\r\n            }\r\n	    }\r\n\r\n        // Proceed only if an article image exists.\r\n        if (isset($ids)) {\r\n\r\n            $ids = implode(\',\',$ids);\r\n          	$rs = safe_rows(\r\n				\'ext,id,thumbnail\',\r\n				\'txp_image\',\r\n				\'id in (\'.$ids.\')\'\r\n			);\r\n\r\n			if ($rs) { // If image exist\r\n				$rnd_number = \'?\'.time(); // Append to src to force reload.\r\n				foreach($rs as $a) {\r\n					extract($a);\r\n					if($thumbnail == 0){\r\n						$image = $id.$ext.$rnd_number;\r\n					}\r\n					else {\r\n						$image = $id.\'t\'.$ext.$rnd_number;\r\n					}\r\n					$str[] =\r\n						\'<li class=\"bot_iu_image_container id\'.$id.\'\">\'.\r\n							\'<img src=\"\'.$image_path.\'/\'.$image.\'\" alt=\"\" />\'.\r\n							\'<span>\'.\r\n								\'<a class=\"bot_image_delete\" href=\"#\" title=\"\'.$bot_image_delete_text.\'\">\'.$bot_image_delete_text.\'</a>\'.\r\n								\' <a class=\"bot_image_edit\" href=\"#\" title=\"\'.$bot_image_edit_text.\'\">\'.$bot_image_edit_text.\'</a>\'.\r\n							\'</span>\'.\r\n						\'</li>\';\r\n				}\r\n				return implode(\'\',$str);\r\n			}\r\n        }\r\n    }\r\n\r\n\r\n/**\r\n	Generates js code\r\n*/\r\n\r\n    function bot_image_upload()\r\n    {\r\n		global $event;\r\n\r\n		if($event != \'article\') {\r\n			return;\r\n		}\r\n\r\n		extract(bot_iu_prefs());		\r\n		$bot_iu_saved_image = bot_image_generate_thumbnail();\r\n\r\n		echo <<<JS_CODE\r\n		<script type=\"text/javascript\" src=\"$bot_iu_ui_path\"></script>\r\n		<script type=\"text/javascript\">\r\n				\r\n			$(document).ready(function() {\r\n				// Modify \'write\' tab\r\n				$(\"$bot_iu_fields\").parent().append(\'<ul class=\"bot_iu_ul_container\"></ul><a class=\"bot_add_image\" href=\"#\" title=\"$bot_choose_image_text\">$bot_choose_image_text</a>\'); // Creates an \'add image\' link.\r\n				$(\"body\").append(\'<div id=\"bot_temporary\">$bot_iu_saved_image</div>\');\r\n				$(\".bot_add_image\").each(function(){ // display saved images\r\n	     			var value = $(this).parents(\"p\").find(\"input\").val();\r\n		            var container = $(this).prev(\'.bot_iu_ul_container\');\r\n					if(value) {\r\n						var ids = value.split(\",\");\r\n						for(var i = 0 ; i < ids.length ; i++) {\r\n		                    var imageId = ids[i];\r\n							if (ids[i]) {\r\n			                    var idClass = \".id\" + ids[i];\r\n								$(\"#bot_temporary \"+idClass).clone().appendTo(container); // clone cos otherwise duplicate images are appended only once\r\n	                        }\r\n     					}\r\n					}\r\n				});\r\n				$(\"#bot_temporary\").remove();\r\n				$(\"$bot_iu_fields\").hide(); // Hide article image input.\r\n\r\n				if (jQuery.ui) {				\r\n			    	$(\".bot_iu_ul_container\").sortable({\r\n						update: function(event, ui) {\r\n							var imgOrder = $(this).sortable(\'toArray\',{attribute:\"class\"}).toString().replace(/bot_iu_image_container id/g,\"\");\r\n							$(this).siblings(\"input\").val(imgOrder);\r\n						}\r\n					});\r\n			    }\r\n\r\n				// When clicking \'add\' or \'edit\' link...\r\n				$(\".bot_add_image, .bot_image_edit\").live(\"click\",function(){\r\n				\r\n					// Set variables\r\n					var selector = $(this); // Clicked link\r\n					var input = selector.parents(\"p\").children(\"input\"); // ...corresponding input\r\n					var p = selector.parents(\"p\"); // ...surrounding p\r\n					var values = input.val().split(\",\"); // existant ids array\r\n		            var backup = p.clone(); // backup for undo\r\n		            \r\n					// Determines if clicked item is single-image or multi\r\n					var clickedId = input.attr(\'id\');\r\n					var monoList = \'$bot_iu_mono_list\';\r\n		            if (monoList.indexOf(clickedId)!= -1) {\r\n		            	var type = \'mono\';\r\n					}\r\n\r\n					// Set the url the iframe must point to.\r\n					if (selector.attr(\"class\") == \'bot_add_image\') { // If .bot_add_image is clicked...\r\n						var iframeUrl = \"index.php?event=image\";\r\n					}\r\n					else {\r\n						// If an edit link is clicked...\r\n						var imageId = $(this).parents(\".bot_iu_image_container\").attr(\"class\").replace(\"bot_iu_image_container id\",\"\");\r\n						var iframeUrl = \"index.php?event=image&step=image_edit&id=\"+imageId;\r\n					}\r\n\r\n					// Fade in Background\r\n				    $(\'body\').append(\'<div id=\"bot_iu_fade\"></div>\'); //Add the fade layer to bottom of the body tag.\r\n				    $(\'#bot_iu_fade\').show().css({\'filter\' : \'alpha(opacity=80)\'}); // show the fade layer -  fix the IE Bug on fading transparencies\r\n\r\n					// Creates an hidden iframe.\r\n					$(\"body\").append(\r\n						\'<div id=\"bot_iu_iframe_container\"\">\' +\r\n							\'<iframe id=\"bot_iu_iframe\" src =\"\' + iframeUrl + \'\" frameborder=\"0\"></iframe>\' +\r\n						\'</div>\'\r\n					);\r\n\r\n	           		// creates \'cancel\' and \'save\' buttons\r\n		            $(\"#bot_iu_iframe\").after(\"<p><a id=\\\"bot_iu_save\\\">$bot_iu_save_text</a><a id=\\\"bot_iu_cancel\\\">$bot_iu_cancel_text</a></p>\");\r\n		            \r\n					// Calculates heights based on window size for vertical centering.\r\n					var windowHeight = $(window).height();\r\n					var containerHeight = (windowHeight * 80) / 100;\r\n					var containerTopMargin = (windowHeight - containerHeight) / 2;\r\n					var iframeHeight = (containerHeight * 78) / 100;\r\n					var loadingTopMargin = (windowHeight / 2) - 30;\r\n					$(\"#bot_iu_iframe_container\").height(containerHeight).css(\"top\", containerTopMargin);\r\n					$(\"#bot_iu_iframe\").height(iframeHeight).css(\"margin-top\", containerTopMargin / 2);\r\n					$(\"#bot_iu_save\").css(\"margin-top\", containerTopMargin / 2);\r\n					$(\"body\").append(\'<p id=\"bot_iu_loading\">loading</p>\');\r\n\r\n\r\n					// Iframe interactions\r\n					$(\"#bot_iu_iframe\").load(function(){\r\n\r\n						// Hides in iframe\r\n						var iframe = $(\"#bot_iu_iframe\").contents();\r\n						iframe.find(\"#pagetop, #end_page, #nav, #messagepane\").hide();\r\n						iframe.find(\"#image-search option[value=author]\").remove(); // remove some options from search\r\n						iframe.find(\"#image-search option[value=id]\").remove();\r\n						iframe.find(\"#image-search option[value=alt]\").remove();\r\n						iframe.find(\"#image-search option[value=caption]\").remove();\r\n						iframe.find(\"#list .actions\").hide();\r\n						iframe.find(\"#list .date\").hide();\r\n						iframe.find(\"#list .tag-build\").hide();\r\n						iframe.find(\"#list .author\").hide();\r\n						iframe.find(\"#list .multi-edit\").hide();\r\n						iframe.find(\".thumbnail-edit\").hide(); // Hides \'upload thumb\'.\r\n						iframe.find(\".thumbnail-alter\").hide(); // Hides \'create thumb\'.\r\n						iframe.find(\"#image-name\").parent().hide(); // Hides \'image name\'\r\n						iframe.find(\"input.publish\").hide(); // Hides original save button\r\n						iframe.find(\"#jbx_div\").remove(); // Removes jbd_multiple_upload\r\n\r\n						// Adds \'add\' colum\r\n						iframe.find(\"#list th:nth-child(8)\").after(\'<th>$bot_add_image_text</th>\');\r\n						iframe.find(\"#list td:nth-child(8)\").after(\r\n							\'<td class=\"add\">\' +\r\n								\'<input type=\"checkbox\" name=\"bot_image_checkbox[]\" class=\"bot_image_checkbox\" />\' +\r\n							\'</td>\');\r\n\r\n						// Checks checkboxes depending on already set cfs.\r\n						if (type == \'mono\') { // if mono reduce values array to last item\r\n							var imageId = values.pop();\r\n			            	values=[];\r\n							values.push(imageId);\r\n					    }\r\n	                    for(var i = 0 ; i < values.length ; i++) { \r\n	                        imageId = values[i];\r\n	                        iframe.find(\"#images_form .id\").filter(function(){\r\n								return $(this).text() == imageId\r\n							;}).siblings(\'.add\').find(\'input.bot_image_checkbox\').attr(\'checked\', true).parents(\"tr\").css(\"background\",\"$bot_iu_row_bg\");\r\n						}\r\n\r\n      					// everything is done, now loader can be hidden and iframe can be shown.\r\n						$(\"#bot_iu_loading\").hide();\r\n						$(\"#bot_iu_iframe_container\").show();\r\n\r\n						// on click\r\n						iframe.find(\".bot_image_checkbox[type=checkbox]\").click(function(){\r\n							var imageId = $(this).parents(\"tr\").find(\"td.id\").text(); // Grabs image id.\r\n							var imageUrl = $(this).parents(\"tr\").find(\"td.thumbnail img\").attr(\'src\'); // Grabs url of currently checked thumb\r\n\r\n							if (this.checked){\r\n                                if (type == \'mono\') {\r\n									iframe.find(\"tr\").css(\"background\",\"none\"); // Eliminates all rows bg.\r\n									iframe.find(\".bot_image_checkbox\").not($(this)).attr(\'checked\', false); // Unchecks all other checkboxes.\r\n									p.find(\".bot_iu_image_container\").remove(); // Removes image container\r\n							    }\r\n							    $(this).parents(\"tr\").css(\"background\",\"$bot_iu_row_bg\"); // Changes checked row bg.\r\n								values.push(imageId); // Inserts new image id.\r\n								p.find(\".bot_iu_ul_container\").append(\r\n									\'<li class=\"bot_iu_image_container id\' + imageId + \'\">\' +\r\n										\'<img src=\"\' + imageUrl + \'\" />\' +\r\n										\'<span>\' +\r\n											\'<a class=\"bot_image_delete\" href=\"#\" title=\"$bot_image_delete_text\">$bot_image_delete_text</a>\' +\r\n											\' <a class=\"bot_image_edit\" href=\"#\" title=\"$bot_image_edit_text\">$bot_image_edit_text</a>\' +\r\n										\'</span>\' +\r\n									\'</li>\'\r\n								);\r\n							}\r\n\r\n							else {\r\n								var arrayIndex = $.inArray(imageId, values); // checks this id index in array\r\n		                        values.splice(arrayIndex,1); // eliminates this id from array\r\n								p.find(\"li[class=bot_iu_image_container id\"+imageId+\"]\").remove(); // Removes thumbnail container.\r\n								$(this).parents(\"tr\").css(\"background\",\"none\"); // Removes background.\r\n							}\r\n						});\r\n\r\n						// Sets again background for selected row.\r\n						iframe.find(\"#list tr:has(input.bot_image_checkbox:checked)\").addClass(\"bot_iu_row_background\");\r\n\r\n						// Avoid FOUC when clicking links and submits.\r\n						iframe.find(\"#list a, input.smallerbox, input.publish\").not(\"#eblcropui a, #eblcropui input\").click(function(){\r\n							 $(\"#bot_iu_iframe_container\").hide();\r\n							 $(\"#bot_iu_loading\").show();\r\n						});\r\n\r\n						// When clicking \'save\' button...\r\n						$(\"#bot_iu_save\").click(function(){\r\n\r\n							var iframe = $(\"#bot_iu_iframe\").contents();\r\n                            if (iframe.find(\".publish\").length) { // we are on edit pane\r\n                            	iframe.find(\".publish\").click();\r\n								var editedImageId = iframe.find(\".publish\").parent().next(\"input[name=id]\").val();\r\n								var imageUrl = iframe.find(\"#image-thumbnail img\").attr(\'src\'); // Grabs the new image thumbnail.\r\n                                if (type == \'mono\') {\r\n					            	values.length = 0;\r\n					            	p.find(\".bot_iu_ul_container li\").remove();\r\n							    }								\r\n								if ($.inArray(editedImageId, values)!=-1) { // When editing an already selected image just refresh image.\r\n									$(\".id\"+editedImageId+\" img\").attr(\'src\', imageUrl);\r\n								}\r\n								else {\r\n                            		values.push(editedImageId);\r\n									p.find(\".bot_iu_ul_container\").append(\r\n										\'<li class=\"bot_iu_image_container id\' + editedImageId + \'\">\' +\r\n											\'<img src=\"\' + imageUrl + \'\" />\' +\r\n											\'<span>\' +\r\n												\'<a class=\"bot_image_delete\" href=\"#\" title=\"$bot_image_delete_text\">$bot_image_delete_text</a>\' +\r\n												\' <a class=\"bot_image_edit\" href=\"#\" title=\"$bot_image_edit_text\">$bot_image_edit_text</a>\' +\r\n											\'</span>\' +\r\n										\'</li>\'\r\n									);\r\n        						}\r\n                            }\r\n                            else { // we are on img list\r\n                                var oldValues = input.val();\r\n                                if (!oldValues[0] && type != \'mono\') { // eliminates first (blank) array item if oldValue is empty\r\n									values.shift();\r\n                                }\r\n                               if (type == \'mono\') {\r\n									var imageId = values.pop();\r\n					            	values=[];\r\n									values.push(imageId);\r\n							    }                             \r\n								input.val(values); // update cf values\r\n    							$(\"#bot_iu_iframe_container, #bot_iu_loading, #bot_iu_fade\").remove();\r\n                            }\r\n						})\r\n						\r\n						// When clicking \'cancel\' button...\r\n						$(\"#bot_iu_cancel\").click(function(){\r\n							p.replaceWith(backup);\r\n			                $(\"#bot_iu_iframe_container, #bot_iu_loading, #bot_iu_fade\").remove();\r\n						})\r\n\r\n					});\r\n					return false;\r\n				});\r\n\r\n			   $(\".bot_image_delete\").live(\'click\',function(){\r\n					var input = $(this).parents(\"p\").children(\"input\");\r\n					var values = input.val().split(\",\"); // existant ids array\r\n					var imageId = $(this).parents(\".bot_iu_image_container\").attr(\"class\").replace(\"bot_iu_image_container id\",\"\"); // current id\r\n					var arrayIndex = $.inArray(imageId, values); // checks this id index in array\r\n		            values.splice(arrayIndex,1); // eliminates this id from array\r\n					input.val(values);  // updates values\r\n					$(this).parents(\".bot_iu_image_container\").remove(); // Removes image container\r\n					return false;\r\n				});\r\n			});\r\n		</script>\r\nJS_CODE;\r\n    }\r\n','//<?\r\n\r\n	if(@txpinterface == \'admin\') {\r\n		register_callback(\'bot_image_upload\',\'article\');\r\n		register_callback(\'bot_image_css\',\'admin_side\',\'head_end\');\r\n 		bot_image_img();\r\n	}\r\n\r\n/*******************************************************************************\r\n	Global preferences - Configuration. Read comments and modify to your needs.\r\n*******************************************************************************/\r\n\r\n	function bot_iu_prefs() {\r\n		return\r\n			array(\r\n				\'bot_iu_fields\' => \'#article-image\', // fields to be used (comma separated | use #custom-n for cfs)\r\n				\'bot_iu_mono_list\' => \'\', // filelds with single image (comma separated | use #custom-n for cfs)\r\n				\'bot_choose_image_text\' => gTxt(\'Choose image\'), // text for \"Choose images\" link and button\r\n				\'bot_image_delete_text\' => gTxt(\'Delete image\'), // text and title for \"delete image\" button\r\n				\'bot_image_edit_text\' => gTxt(\'Edit image\'), // text and title for \"edit image\" button\"\r\n				\'bot_add_image_text\' => gTxt(\'Add\'), // text for \"add image\" checkbox\r\n				\'bot_iu_save_text\' => gTxt(\'save\'), // text for \"Save\" button\"\r\n				\'bot_iu_cancel_text\' => gTxt(\'cancel\'), // text for \"Cancel\" button\"\r\n				\'bot_iu_row_bg\' => \'#eaeaea\', // selected row background\r\n				\'bot_iu_ui_path\' => \'jquery-ui-1.8.9.custom.min.js\', // path to the jQuery ui script. Defaults to \'textpattern\' directory. Set to \'\' if ui already loaded\r\n			);\r\n	}\r\n\r\n/**\r\n	CSS for the image upload. You are free to modify these\r\n	to match your own backend theme.\r\n*/\r\n\r\n	function bot_image_css() {\r\n\r\n		global $event;\r\n		if($event != \'article\') { // Outputs css only in \'write\' tab.\r\n			return;\r\n		}\r\n\r\n		echo \'<style type=\"text/css\">\r\n				.bot_image_delete {\r\n					background: url(\"?bot_image_img=delete\") top center no-repeat;\r\n					display:inline-block;\r\n					text-indent: -99999px;\r\n					width:15px;\r\n					height:20px;\r\n				}\r\n				.bot_image_edit {\r\n					background:url(\"?bot_image_img=edit\") top center no-repeat;\r\n					display:inline-block;\r\n					text-indent:-99999px;\r\n					width:15px;\r\n					height:20px;\r\n					margin-right: 5px;\r\n				}\r\n				#bot_iu_loading {\r\n					background:#000 url(\"?bot_image_img=bot_iu_loading\") center center no-repeat;\r\n					text-indent:-99999px;\r\n					width:50px;\r\n					height:50px;\r\n					padding:10px;\r\n					position:fixed;\r\n					left:50%;\r\n					margin-left:-30px;\r\n					top:50%;\r\n					margin-top:-30px;\r\n					z-index:9999;\r\n					-moz-border-radius:10px;\r\n					-webkit-border-radius:10px;\r\n					border-radius: 10px;\r\n				}\r\n				#bot_iu_fade {\r\n					display: none;\r\n					background: #000;\r\n					position: fixed; left: 0; top: 0;\r\n					width: 100%; height: 100%;\r\n					opacity: .80;\r\n					z-index: 999;\r\n				}\r\n				#bot_iu_iframe {\r\n					width:800px;\r\n				}\r\n				#bot_iu_iframe_container {\r\n				    /* height and margin-top are set by js */\r\n				    display:none;\r\n				    position:fixed;\r\n				    left:50%;\r\n				    z-index: 99999;\r\n					overflow: hidden;\r\n					background: #f4f4f4;\r\n					width:800px;\r\n					padding:0 20px;\r\n					margin-left: -400px;\r\n					text-align:right;\r\n					-moz-border-radius:5px;\r\n					-webkit-border-radius:10px;\r\n					border-radius: 10px;\r\n					-moz-box-shadow: 0 0 20px #000;\r\n					-webkit-box-shadow: 0 0 20px #000;\r\n					box-shadow: 0 0 20px #000;\r\n				}\r\n				#bot_iu_save,\r\n				#bot_iu_cancel {\r\n					background:#666;\r\n					color:#fff;\r\n					font-weight:bold;\r\n					padding:5px 10px;\r\n					margin-left:5px;\r\n					display:inline-block;\r\n					cursor:pointer;\r\n					-moz-border-radius:5px;\r\n					-webkit-border-radius:5px;\r\n					border-radius:5px;\r\n				}\r\n				#bot_iu_save:hover,\r\n				#bot_iu_cancel:hover {\r\n					background:#333;\r\n					text-decoration:none;\r\n				}\r\n				.bot_iu_ul_container {\r\n					margin:0;\r\n				}\r\n				.bot_iu_image_container {\r\n					display:inline-block;\r\n					border:solid #eaeaea 1px;\r\n					background: #fff;\r\n					padding:10px 10px 0;\r\n					-moz-box-shadow:2px 2px 5px #ccc;\r\n					-webkit-box-shadow:2px 2px 5px #ccc;\r\n					box-shadow:2px 2px 5px #ccc;\r\n				}\r\n				.bot_iu_image_container span {\r\n					display:block;\r\n					overflow:hidden;\r\n					padding-top:5px;\r\n				}\r\n				.bot_add_image {\r\n					display:block;\r\n				}\r\n			</style>\r\n			\r\n			<!--[if lte IE 7]>\r\n				<style>\r\n					/*-- styling for fucking ie7 and below --*/\r\n					.bot_iu_image_container {\r\n						display:inline;\r\n					}\r\n					.bot_image_delete,\r\n					.bot_image_edit {\r\n						float:left;\r\n					}\r\n				</style>\r\n			<![endif]-->\r\n			\r\n			<!--[if lte IE 6]>\r\n				<style>\r\n					/*-- minimal styling for fucking ie6 and below --*/\r\n					#bot_iu_fade,\r\n					#bot_iu_loading,\r\n					#bot_iu_iframe_container {\r\n						position: absolute;\r\n					}\r\n					#bot_iu_iframe_container {\r\n						border: solid #ccc thick;\r\n					}\r\n				</style>\r\n			<![endif]-->\';\r\n	}\r\n\r\n/**\r\n	Generates and stores the images required by the design.\r\n	Image URI is: http://example.com/textpattern/?bot_image_img=delete|edit|file\r\n*/\r\n\r\n	function bot_image_img() {\r\n\r\n 	global $event;\r\n		if($event != \'article\') { // Generates images only in \'write\' tab.\r\n			return;\r\n		}\r\n		$image = gps(\'bot_image_img\');\r\n\r\n		if(!$image)\r\n			return;\r\n\r\n		switch($image) {\r\n			case \'delete\':\r\n				$file = \'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABEElEQVR42mL4//8/Ayn4zJkzXMh8gABiYkACZ8+elQdibQYcACqXCqTtYGIAAcQIMgWmGUg9gIrrGBsbX8Wi+QqUuxKIG4FqrgMEENgANM0M6IagaYaBAiCeDBBAMAM4gJyvQMyEbgiURtf8F4g5gRb8BgggZC+ADPkCxMwM+AFIMw9Q8w8QByCA4DZCBXigCojSDAIAAYTiZCRD/mHR/A9dMwgABBATFoXKOMSZoHIoACCAmPBEFTZwBT2dAAQQEwHNf7F4B8UQgABiIqAZFB7cWAIWbghAAMFcIIYrtPHEDlgPQAAxQUN/P5BywhXaWAxxguphAAgg9JzmCMQceHIiB0gNshhAAMFTIrkAIMAA7k7JUu0YckQAAAAASUVORK5CYII=\';\r\n				break;\r\n			case \'edit\':\r\n				$file = \'iVBORw0KGgoAAAANSUhEUgAAABMAAAAUCAMAAABYi/ZGAAAABGdBTUEAAK/INwWK6QAAABl0RVh0 U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACiUExURf7+/v39/bOzs+rq6uHh4dXV1c3N zb6+vqioqLKysq6urqmpqfb29tDQ0O7u7vPz8+3t7d7e3q2trc/Pz7CwsLm5udPT09HR0d3d3fHx 8fT09MXFxaqqqsDAwNra2tTU1Ovr67GxsfLy8qysrNfX17i4uLe3t8HBwaenp/r6+uzs7ODg4N/f 3+/v78nJyenp6bu7u7+/v8zMzNnZ2dLS0v///181u00AAAA2dFJOU/////////////////////// ////////////////////////////////////////////////AKGPTjEAAADaSURBVHjaYjDFBAAB xIDEZuRl5wPRAAGEJMYgziVixANkAAQQkpi4mqoGkzSQARBACDE2WX0TIQ4mIAsggOBiwoZaPLrS 3CxAJkAAwcSE2QX4FYxFJUB8gACCirGx8ykxyzMJgrkAAQQR41UXkGRm5RRkBPMAAggsJmYgKcXM qigBETIFCCCwmLKKnhSriA5UyBQggMBiHKIyLFzaMCFTgAACi3ELMXGyIFwKEEBgFpsYvxyShwAC CGK5Jkq4AAQQA5awAgggbGIAAYRNDCCAsIkBBBA2MYAAAwCXW0H+487c7QAAAABJRU5ErkJggg==\';\r\n				break;\r\n			default:\r\n				$file = \'R0lGODlhHwAfAPUAAAAAAP///xYWFiwsLEJCQlBQUFxcXCIiIkZGRmRkZBoaGiYmJlRUVF5eXk5OTjIyMggICFZWVioqKhgYGMjIyNjY2K6urjo6Oo6OjmxsbKioqAQEBJaWlri4uDg4OAYGBra2tszMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAHwAfAAAG/0CAcEgUDAgFA4BiwSQexKh0eEAkrldAZbvlOD5TqYKALWu5XIwnPFwwymY0GsRgAxrwuJwbCi8aAHlYZ3sVdwtRCm8JgVgODwoQAAIXGRpojQwKRGSDCRESYRsGHYZlBFR5AJt2a3kHQlZlERN2QxMRcAiTeaG2QxJ5RnAOv1EOcEdwUMZDD3BIcKzNq3BJcJLUABBwStrNBtjf3GUGBdLfCtadWMzUz6cDxN/IZQMCvdTBcAIAsli0jOHSJeSAqmlhNr0awo7RJ19TJORqdAXVEEVZyjyKtE3Bg3oZE2iK8oeiKkFZGiCaggelSTiA2LhxiZLBSjZjBL2siNBOFQ84LxHA+mYEiRJzBO7ZCQIAIfkECQoAAAAsAAAAAB8AHwAABv9AgHBIFAwIBQPAUCAMBMSodHhAJK5XAPaKOEynCsIWqx0nCIrvcMEwZ90JxkINaMATZXfju9jf82YAIQxRCm14Ww4PChAAEAoPDlsAFRUgHkRiZAkREmoSEXiVlRgfQgeBaXRpo6MOQlZbERN0Qx4drRUcAAJmnrVDBrkVDwNjr8BDGxq5Z2MPyUQZuRgFY6rRABe5FgZjjdm8uRTh2d5b4NkQY0zX5QpjTc/lD2NOx+WSW0++2RJmUGJhmZVsQqgtCE6lqpXGjBchmt50+hQKEAEiht5gUcTIESR9GhlgE9IH0BiTkxrMmWIHDkose9SwcQlHDsOIk9ygiVbl5JgMLuV4HUmypMkTOkEAACH5BAkKAAAALAAAAAAfAB8AAAb/QIBwSBQMCAUDwFAgDATEqHR4QCSuVwD2ijhMpwrCFqsdJwiK73DBMGfdCcZCDWjAE2V347vY3/NmdXNECm14Ww4PChAAEAoPDltlDGlDYmQJERJqEhGHWARUgZVqaWZeAFZbERN0QxOeWwgAAmabrkMSZkZjDrhRkVtHYw+/RA9jSGOkxgpjSWOMxkIQY0rT0wbR2LQV3t4UBcvcF9/eFpdYxdgZ5hUYA73YGxruCbVjt78G7hXFqlhY/fLQwR0HIQdGuUrTz5eQdIc0cfIEwByGD0MKvcGSaFGjR8GyeAPhIUofQGNQSgrB4IsdOCqx7FHDBiYcOQshYjKDxliVDpRjunCjdSTJkiZP6AQBACH5BAkKAAAALAAAAAAfAB8AAAb/QIBwSBQMCAUDwFAgDATEqHR4QCSuVwD2ijhMpwrCFqsdJwiK73DBMGfdCcZCDWjAE2V347vY3/NmdXNECm14Ww4PChAAEAoPDltlDGlDYmQJERJqEhGHWARUgZVqaWZeAFZbERN0QxOeWwgAAmabrkMSZkZjDrhRkVtHYw+/RA9jSGOkxgpjSWOMxkIQY0rT0wbR2I3WBcvczltNxNzIW0693MFYT7bTumNQqlisv7BjswAHo64egFdQAbj0RtOXDQY6VAAUakihN1gSLaJ1IYOGChgXXqEUpQ9ASRlDYhT0xQ4cACJDhqDD5mRKjCAYuArjBmVKDP9+VRljMyMHDwcfuBlBooSCBQwJiqkJAgAh+QQJCgAAACwAAAAAHwAfAAAG/0CAcEgUDAgFA8BQIAwExKh0eEAkrlcA9oo4TKcKwharHScIiu9wwTBn3QnGQg1owBNld+O72N/zZnVzRApteFsODwoQABAKDw5bZQxpQ2JkCRESahIRh1gEVIGVamlmXgBWWxETdEMTnlsIAAJmm65DEmZGYw64UZFbR2MPv0QPY0hjpMYKY0ljjMZCEGNK09MG0diN1gXL3M5bTcTcyFtOvdzBWE+207pjUKpYrL+wY7MAB4EerqZjUAG4lKVCBwMbvnT6dCXUkEIFK0jUkOECFEeQJF2hFKUPAIkgQwIaI+hLiJAoR27Zo4YBCJQgVW4cpMYDBpgVZKL59cEBhw+U+QROQ4bBAoUlTZ7QCQIAIfkECQoAAAAsAAAAAB8AHwAABv9AgHBIFAwIBQPAUCAMBMSodHhAJK5XAPaKOEynCsIWqx0nCIrvcMEwZ90JxkINaMATZXfju9jf82Z1c0QKbXhbDg8KEAAQCg8OW2UMaUNiZAkREmoSEYdYBFSBlWppZl4AVlsRE3RDE55bCAACZpuuQxJmRmMOuFGRW0djD79ED2NIY6TGCmNJY4zGQhBjStPTFBXb21DY1VsGFtzbF9gAzlsFGOQVGefIW2LtGhvYwVgDD+0V17+6Y6BwaNfBwy9YY2YBcMAPnStTY1B9YMdNiyZOngCFGuIBxDZAiRY1eoTvE6UoDEIAGrNSUoNBUuzAaYlljxo2M+HIeXiJpRsRNMaq+JSFCpsRJEqYOPH2JQgAIfkECQoAAAAsAAAAAB8AHwAABv9AgHBIFAwIBQPAUCAMBMSodHhAJK5XAPaKOEynCsIWqx0nCIrvcMEwZ90JxkINaMATZXfjywjlzX9jdXNEHiAVFX8ODwoQABAKDw5bZQxpQh8YiIhaERJqEhF4WwRDDpubAJdqaWZeAByoFR0edEMTolsIAA+yFUq2QxJmAgmyGhvBRJNbA5qoGcpED2MEFrIX0kMKYwUUslDaj2PA4soGY47iEOQFY6vS3FtNYw/m1KQDYw7mzFhPZj5JGzYGipUtESYowzVmF4ADgOCBCZTgFQAxZBJ4AiXqT6ltbUZhWdToUSR/Ii1FWbDnDkUyDQhJsQPn5ZU9atjUhCPHVhgTNy/RSKsiqKFFbUaQKGHiJNyXIAAh+QQJCgAAACwAAAAAHwAfAAAG/0CAcEh8JDAWCsBQIAwExKhU+HFwKlgsIMHlIg7TqQeTLW+7XYIiPGSAymY0mrFgA0LwuLzbCC/6eVlnewkADXVECgxcAGUaGRdQEAoPDmhnDGtDBJcVHQYbYRIRhWgEQwd7AB52AGt7YAAIchETrUITpGgIAAJ7ErdDEnsCA3IOwUSWaAOcaA/JQ0amBXKa0QpyBQZyENFCEHIG39HcaN7f4WhM1uTZaE1y0N/TacZoyN/LXU+/0cNyoMxCUytYLjm8AKSS46rVKzmxADhjlCACMFGkBiU4NUQRxS4OHijwNqnSJS6ZovzRyJAQo0NhGrgs5bIPmwWLCLHsQsfhxBWTe9QkOzCwC8sv5Ho127akyRM7QQAAOwAAAAAAAAAAAA==\';\r\n		}\r\n\r\n		ob_start();\r\n		ob_end_clean();\r\n		header(\'Content-type: image/gif\');\r\n		echo base64_decode($file);\r\n		exit();\r\n	}\r\n\r\n\r\n    function bot_image_generate_thumbnail()\r\n    {\r\n		global $prefs, $step;\r\n		extract(bot_iu_prefs());\r\n		$image_path = hu.$prefs[\'img_dir\'];\r\n		$article_id = gps(\'ID\'); // Fetch article id from $_GET, if any, or sets it to \'\'\r\n    	$fields_array = explode(\",\", $bot_iu_fields); // tranforms in array\r\n		for ($i =0; $i < count($fields_array); $i++) { // changes array values to be used with urls and db\r\n			$current_field = trim($fields_array[$i]);  \r\n			$current_field = ($current_field == \'#article-image\') ? \'Image\': str_replace(\'#custom-\', \'custom_\', $current_field);\r\n			$fields_array[$i] = $current_field; // reinserts modified value\r\n		}\r\n\r\n        if ($step == \'edit\' && $article_id) { // when opening an already existant article\r\n			$fields_string = implode(\',\', $fields_array);\r\n            $values = safe_row($fields_string, \'textpattern\', \'ID = \'. $article_id);\r\n    	}\r\n\r\n    	elseif($step == \'create\' || $step == \'edit\') { // when hitting \'save\'\r\n			for ($i =0; $i < count($fields_array); $i++) { // fetch all image ids and put in array \'values\'\r\n				$current = $fields_array[$i];  \r\n				$values[] = gps($current_field);\r\n			}\r\n    	}\r\n		\r\n		// creates a numerical array of all images for current article\r\n		$values = array_filter(array_values($values)); // convert to numerical array and remove empty values		\r\n		$values = explode(\',\', implode(\',\', $values)); // only one value per array key\r\n		// Sanitizes values\r\n      	foreach($values as $value) {\r\n		    if(is_numeric($value)) {\r\n			    $ids[] = \"\'\".doSlash($value).\"\'\";\r\n            }\r\n	    }\r\n\r\n        // Proceed only if an article image exists.\r\n        if (isset($ids)) {\r\n\r\n            $ids = implode(\',\',$ids);\r\n          	$rs = safe_rows(\r\n				\'ext,id,thumbnail\',\r\n				\'txp_image\',\r\n				\'id in (\'.$ids.\')\'\r\n			);\r\n\r\n			if ($rs) { // If image exist\r\n				$rnd_number = \'?\'.time(); // Append to src to force reload.\r\n				foreach($rs as $a) {\r\n					extract($a);\r\n					if($thumbnail == 0){\r\n						$image = $id.$ext.$rnd_number;\r\n					}\r\n					else {\r\n						$image = $id.\'t\'.$ext.$rnd_number;\r\n					}\r\n					$str[] =\r\n						\'<li class=\"bot_iu_image_container id\'.$id.\'\">\'.\r\n							\'<img src=\"\'.$image_path.\'/\'.$image.\'\" alt=\"\" />\'.\r\n							\'<span>\'.\r\n								\'<a class=\"bot_image_delete\" href=\"#\" title=\"\'.$bot_image_delete_text.\'\">\'.$bot_image_delete_text.\'</a>\'.\r\n								\' <a class=\"bot_image_edit\" href=\"#\" title=\"\'.$bot_image_edit_text.\'\">\'.$bot_image_edit_text.\'</a>\'.\r\n							\'</span>\'.\r\n						\'</li>\';\r\n				}\r\n				return implode(\'\',$str);\r\n			}\r\n        }\r\n    }\r\n\r\n\r\n/**\r\n	Generates js code\r\n*/\r\n\r\n    function bot_image_upload()\r\n    {\r\n		global $event;\r\n\r\n		if($event != \'article\') {\r\n			return;\r\n		}\r\n\r\n		extract(bot_iu_prefs());		\r\n		$bot_iu_saved_image = bot_image_generate_thumbnail();\r\n\r\n		echo <<<JS_CODE\r\n		<script type=\"text/javascript\" src=\"$bot_iu_ui_path\"></script>\r\n		<script type=\"text/javascript\">\r\n				\r\n			$(document).ready(function() {\r\n				// Modify \'write\' tab\r\n				$(\"$bot_iu_fields\").parent().append(\'<ul class=\"bot_iu_ul_container\"></ul><a class=\"bot_add_image\" href=\"#\" title=\"$bot_choose_image_text\">$bot_choose_image_text</a>\'); // Creates an \'add image\' link.\r\n				$(\"body\").append(\'<div id=\"bot_temporary\">$bot_iu_saved_image</div>\');\r\n				$(\".bot_add_image\").each(function(){ // display saved images\r\n	     			var value = $(this).parents(\"p\").find(\"input\").val();\r\n		            var container = $(this).prev(\'.bot_iu_ul_container\');\r\n					if(value) {\r\n						var ids = value.split(\",\");\r\n						for(var i = 0 ; i < ids.length ; i++) {\r\n		                    var imageId = ids[i];\r\n							if (ids[i]) {\r\n			                    var idClass = \".id\" + ids[i];\r\n								$(\"#bot_temporary \"+idClass).clone().appendTo(container); // clone cos otherwise duplicate images are appended only once\r\n	                        }\r\n     					}\r\n					}\r\n				});\r\n				$(\"#bot_temporary\").remove();\r\n				$(\"$bot_iu_fields\").hide(); // Hide article image input.\r\n\r\n				if (jQuery.ui) {				\r\n			    	$(\".bot_iu_ul_container\").sortable({\r\n						update: function(event, ui) {\r\n							var imgOrder = $(this).sortable(\'toArray\',{attribute:\"class\"}).toString().replace(/bot_iu_image_container id/g,\"\");\r\n							$(this).siblings(\"input\").val(imgOrder);\r\n						}\r\n					});\r\n			    }\r\n\r\n				// When clicking \'add\' or \'edit\' link...\r\n				$(\".bot_add_image, .bot_image_edit\").live(\"click\",function(){\r\n				\r\n					// Set variables\r\n					var selector = $(this); // Clicked link\r\n					var input = selector.parents(\"p\").children(\"input\"); // ...corresponding input\r\n					var p = selector.parents(\"p\"); // ...surrounding p\r\n					var values = input.val().split(\",\"); // existant ids array\r\n		            var backup = p.clone(); // backup for undo\r\n		            \r\n					// Determines if clicked item is single-image or multi\r\n					var clickedId = input.attr(\'id\');\r\n					var monoList = \'$bot_iu_mono_list\';\r\n		            if (monoList.indexOf(clickedId)!= -1) {\r\n		            	var type = \'mono\';\r\n					}\r\n\r\n					// Set the url the iframe must point to.\r\n					if (selector.attr(\"class\") == \'bot_add_image\') { // If .bot_add_image is clicked...\r\n						var iframeUrl = \"index.php?event=image\";\r\n					}\r\n					else {\r\n						// If an edit link is clicked...\r\n						var imageId = $(this).parents(\".bot_iu_image_container\").attr(\"class\").replace(\"bot_iu_image_container id\",\"\");\r\n						var iframeUrl = \"index.php?event=image&step=image_edit&id=\"+imageId;\r\n					}\r\n\r\n					// Fade in Background\r\n				    $(\'body\').append(\'<div id=\"bot_iu_fade\"></div>\'); //Add the fade layer to bottom of the body tag.\r\n				    $(\'#bot_iu_fade\').show().css({\'filter\' : \'alpha(opacity=80)\'}); // show the fade layer -  fix the IE Bug on fading transparencies\r\n\r\n					// Creates an hidden iframe.\r\n					$(\"body\").append(\r\n						\'<div id=\"bot_iu_iframe_container\"\">\' +\r\n							\'<iframe id=\"bot_iu_iframe\" src =\"\' + iframeUrl + \'\" frameborder=\"0\"></iframe>\' +\r\n						\'</div>\'\r\n					);\r\n\r\n	           		// creates \'cancel\' and \'save\' buttons\r\n		            $(\"#bot_iu_iframe\").after(\"<p><a id=\\\"bot_iu_save\\\">$bot_iu_save_text</a><a id=\\\"bot_iu_cancel\\\">$bot_iu_cancel_text</a></p>\");\r\n		            \r\n					// Calculates heights based on window size for vertical centering.\r\n					var windowHeight = $(window).height();\r\n					var containerHeight = (windowHeight * 80) / 100;\r\n					var containerTopMargin = (windowHeight - containerHeight) / 2;\r\n					var iframeHeight = (containerHeight * 78) / 100;\r\n					var loadingTopMargin = (windowHeight / 2) - 30;\r\n					$(\"#bot_iu_iframe_container\").height(containerHeight).css(\"top\", containerTopMargin);\r\n					$(\"#bot_iu_iframe\").height(iframeHeight).css(\"margin-top\", containerTopMargin / 2);\r\n					$(\"#bot_iu_save\").css(\"margin-top\", containerTopMargin / 2);\r\n					$(\"body\").append(\'<p id=\"bot_iu_loading\">loading</p>\');\r\n\r\n\r\n					// Iframe interactions\r\n					$(\"#bot_iu_iframe\").load(function(){\r\n\r\n						// Hides in iframe\r\n						var iframe = $(\"#bot_iu_iframe\").contents();\r\n						iframe.find(\"#pagetop, #end_page, #nav, #messagepane\").hide();\r\n						iframe.find(\"#image-search option[value=author]\").remove(); // remove some options from search\r\n						iframe.find(\"#image-search option[value=id]\").remove();\r\n						iframe.find(\"#image-search option[value=alt]\").remove();\r\n						iframe.find(\"#image-search option[value=caption]\").remove();\r\n						iframe.find(\"#list .actions\").hide();\r\n						iframe.find(\"#list .date\").hide();\r\n						iframe.find(\"#list .tag-build\").hide();\r\n						iframe.find(\"#list .author\").hide();\r\n						iframe.find(\"#list .multi-edit\").hide();\r\n						iframe.find(\".thumbnail-edit\").hide(); // Hides \'upload thumb\'.\r\n						iframe.find(\".thumbnail-alter\").hide(); // Hides \'create thumb\'.\r\n						iframe.find(\"#image-name\").parent().hide(); // Hides \'image name\'\r\n						iframe.find(\"input.publish\").hide(); // Hides original save button\r\n						iframe.find(\"#jbx_div\").remove(); // Removes jbd_multiple_upload\r\n\r\n						// Adds \'add\' colum\r\n						iframe.find(\"#list th:nth-child(8)\").after(\'<th>$bot_add_image_text</th>\');\r\n						iframe.find(\"#list td:nth-child(8)\").after(\r\n							\'<td class=\"add\">\' +\r\n								\'<input type=\"checkbox\" name=\"bot_image_checkbox[]\" class=\"bot_image_checkbox\" />\' +\r\n							\'</td>\');\r\n\r\n						// Checks checkboxes depending on already set cfs.\r\n						if (type == \'mono\') { // if mono reduce values array to last item\r\n							var imageId = values.pop();\r\n			            	values=[];\r\n							values.push(imageId);\r\n					    }\r\n	                    for(var i = 0 ; i < values.length ; i++) { \r\n	                        imageId = values[i];\r\n	                        iframe.find(\"#images_form .id\").filter(function(){\r\n								return $(this).text() == imageId\r\n							;}).siblings(\'.add\').find(\'input.bot_image_checkbox\').attr(\'checked\', true).parents(\"tr\").css(\"background\",\"$bot_iu_row_bg\");\r\n						}\r\n\r\n      					// everything is done, now loader can be hidden and iframe can be shown.\r\n						$(\"#bot_iu_loading\").hide();\r\n						$(\"#bot_iu_iframe_container\").show();\r\n\r\n						// on click\r\n						iframe.find(\".bot_image_checkbox[type=checkbox]\").click(function(){\r\n							var imageId = $(this).parents(\"tr\").find(\"td.id\").text(); // Grabs image id.\r\n							var imageUrl = $(this).parents(\"tr\").find(\"td.thumbnail img\").attr(\'src\'); // Grabs url of currently checked thumb\r\n\r\n							if (this.checked){\r\n                                if (type == \'mono\') {\r\n									iframe.find(\"tr\").css(\"background\",\"none\"); // Eliminates all rows bg.\r\n									iframe.find(\".bot_image_checkbox\").not($(this)).attr(\'checked\', false); // Unchecks all other checkboxes.\r\n									p.find(\".bot_iu_image_container\").remove(); // Removes image container\r\n							    }\r\n							    $(this).parents(\"tr\").css(\"background\",\"$bot_iu_row_bg\"); // Changes checked row bg.\r\n								values.push(imageId); // Inserts new image id.\r\n								p.find(\".bot_iu_ul_container\").append(\r\n									\'<li class=\"bot_iu_image_container id\' + imageId + \'\">\' +\r\n										\'<img src=\"\' + imageUrl + \'\" />\' +\r\n										\'<span>\' +\r\n											\'<a class=\"bot_image_delete\" href=\"#\" title=\"$bot_image_delete_text\">$bot_image_delete_text</a>\' +\r\n											\' <a class=\"bot_image_edit\" href=\"#\" title=\"$bot_image_edit_text\">$bot_image_edit_text</a>\' +\r\n										\'</span>\' +\r\n									\'</li>\'\r\n								);\r\n							}\r\n\r\n							else {\r\n								var arrayIndex = $.inArray(imageId, values); // checks this id index in array\r\n		                        values.splice(arrayIndex,1); // eliminates this id from array\r\n								p.find(\"li[class=bot_iu_image_container id\"+imageId+\"]\").remove(); // Removes thumbnail container.\r\n								$(this).parents(\"tr\").css(\"background\",\"none\"); // Removes background.\r\n							}\r\n						});\r\n\r\n						// Sets again background for selected row.\r\n						iframe.find(\"#list tr:has(input.bot_image_checkbox:checked)\").addClass(\"bot_iu_row_background\");\r\n\r\n						// Avoid FOUC when clicking links and submits.\r\n						iframe.find(\"#list a, input.smallerbox, input.publish\").not(\"#eblcropui a, #eblcropui input\").click(function(){\r\n							 $(\"#bot_iu_iframe_container\").hide();\r\n							 $(\"#bot_iu_loading\").show();\r\n						});\r\n\r\n						// When clicking \'save\' button...\r\n						$(\"#bot_iu_save\").click(function(){\r\n\r\n							var iframe = $(\"#bot_iu_iframe\").contents();\r\n                            if (iframe.find(\".publish\").length) { // we are on edit pane\r\n                            	iframe.find(\".publish\").click();\r\n								var editedImageId = iframe.find(\".publish\").parent().next(\"input[name=id]\").val();\r\n								var imageUrl = iframe.find(\"#image-thumbnail img\").attr(\'src\'); // Grabs the new image thumbnail.\r\n                                if (type == \'mono\') {\r\n					            	values.length = 0;\r\n					            	p.find(\".bot_iu_ul_container li\").remove();\r\n							    }								\r\n								if ($.inArray(editedImageId, values)!=-1) { // When editing an already selected image just refresh image.\r\n									$(\".id\"+editedImageId+\" img\").attr(\'src\', imageUrl);\r\n								}\r\n								else {\r\n                            		values.push(editedImageId);\r\n									p.find(\".bot_iu_ul_container\").append(\r\n										\'<li class=\"bot_iu_image_container id\' + editedImageId + \'\">\' +\r\n											\'<img src=\"\' + imageUrl + \'\" />\' +\r\n											\'<span>\' +\r\n												\'<a class=\"bot_image_delete\" href=\"#\" title=\"$bot_image_delete_text\">$bot_image_delete_text</a>\' +\r\n												\' <a class=\"bot_image_edit\" href=\"#\" title=\"$bot_image_edit_text\">$bot_image_edit_text</a>\' +\r\n											\'</span>\' +\r\n										\'</li>\'\r\n									);\r\n        						}\r\n                            }\r\n                            else { // we are on img list\r\n                                var oldValues = input.val();\r\n                                if (!oldValues[0] && type != \'mono\') { // eliminates first (blank) array item if oldValue is empty\r\n									values.shift();\r\n                                }\r\n                               if (type == \'mono\') {\r\n									var imageId = values.pop();\r\n					            	values=[];\r\n									values.push(imageId);\r\n							    }                             \r\n								input.val(values); // update cf values\r\n    							$(\"#bot_iu_iframe_container, #bot_iu_loading, #bot_iu_fade\").remove();\r\n                            }\r\n						})\r\n						\r\n						// When clicking \'cancel\' button...\r\n						$(\"#bot_iu_cancel\").click(function(){\r\n							p.replaceWith(backup);\r\n			                $(\"#bot_iu_iframe_container, #bot_iu_loading, #bot_iu_fade\").remove();\r\n						})\r\n\r\n					});\r\n					return false;\r\n				});\r\n\r\n			   $(\".bot_image_delete\").live(\'click\',function(){\r\n					var input = $(this).parents(\"p\").children(\"input\");\r\n					var values = input.val().split(\",\"); // existant ids array\r\n					var imageId = $(this).parents(\".bot_iu_image_container\").attr(\"class\").replace(\"bot_iu_image_container id\",\"\"); // current id\r\n					var arrayIndex = $.inArray(imageId, values); // checks this id index in array\r\n		            values.splice(arrayIndex,1); // eliminates this id from array\r\n					input.val(values);  // updates values\r\n					$(this).parents(\".bot_iu_image_container\").remove(); // Removes image container\r\n					return false;\r\n				});\r\n			});\r\n		</script>\r\nJS_CODE;\r\n    }\r\n','13f83af5d1253f5b60806e169750d986',3,5,0),