Merge branch 'develop' into VCL-1114_misc_small_web_updates
diff --git a/web/.ht-inc/authmethods/ldapauth.php b/web/.ht-inc/authmethods/ldapauth.php
index 1c2ee53..3848ebe 100644
--- a/web/.ht-inc/authmethods/ldapauth.php
+++ b/web/.ht-inc/authmethods/ldapauth.php
@@ -257,7 +257,7 @@
 function validateLDAPUser($type, $loginid) {
 	global $authMechs;
 	$auth = $authMechs[$type];
-	$savehdlr = set_error_handler(create_function('', ''));
+	$savehdlr = set_error_handler(function() {});
 	if(! ($fh = fsockopen($auth['server'], 636, $errno, $errstr, 5)))
 		return -1;
 	set_error_handler($savehdlr);
diff --git a/web/.ht-inc/blockallocations.php b/web/.ht-inc/blockallocations.php
index 9bf25e2..ed0fffa 100644
--- a/web/.ht-inc/blockallocations.php
+++ b/web/.ht-inc/blockallocations.php
@@ -1448,15 +1448,15 @@
 	$rt .= "title=\"" . i("Block Allocation Times") . "\">\n";
 	$rt .= "<h2>" . i("Block Allocation Times") . "</h2>\n";
 	$rt .= "<table dojoType=\"dojox.grid.DataGrid\" jsId=\"blockTimesGrid\" sortInfo=1 ";
-	$rt .= "style=\"width: 278px; height: 200px;\">\n";
+	$rt .= "style=\"width: 328px; height: 200px;\">\n";
 	$rt .= "<script type=\"dojo/method\" event=\"onStyleRow\" args=\"row\">\n";
 	$rt .= "blockTimeRowStyle(row);\n";
 	$rt .= "</script>\n";
 	$rt .= "<thead>\n";
 	$rt .= "<tr>\n";
-	$rt .= "<th field=\"start\" width=\"65px\" formatter=\"blockTimesGridDate\">" . i("Date") . "</th>\n";
-	$rt .= "<th field=\"start\" width=\"54px\" formatter=\"blockTimesGridStart\">" . i("Start") . "</th>\n";
-	$rt .= "<th field=\"end\" width=\"54px\" formatter=\"blockTimesGridEnd\">" . i("End") . "</th>\n";
+	$rt .= "<th field=\"start\" width=\"70px\" formatter=\"blockTimesGridDate\">" . i("Date") . "</th>\n";
+	$rt .= "<th field=\"start\" width=\"85px\" formatter=\"blockTimesGridStart\">" . i("Start") . "</th>\n";
+	$rt .= "<th field=\"end\" width=\"85px\" formatter=\"blockTimesGridEnd\">" . i("End") . "</th>\n";
 	$rt .= "<th field=\"delbtn\" width=\"60px\">" . i("Skip") . "</th>\n";
 	$rt .= "</tr>\n";
 	$rt .= "</thead>\n";
@@ -1741,17 +1741,17 @@
 	$rt .= i("Block Allocation Times") . "\">\n";
 	$rt .= "<h2>" . i("Block Allocation Times") . "</h2>\n";
 	$rt .= "<table dojoType=\"dojox.grid.DataGrid\" jsId=\"blockTimesGrid\" sortInfo=1 ";
-	$rt .= "style=\"width: 278px; height: 200px;\">\n";
+	$rt .= "style=\"width: 328px; height: 200px;\">\n";
 	$rt .= "<script type=\"dojo/method\" event=\"onStyleRow\" args=\"row\">\n";
 	$rt .= "blockTimeRowStyle(row);\n";
 	$rt .= "</script>\n";
 	$rt .= "<thead>\n";
 	$rt .= "<tr>\n";
-	$rt .= "<th field=\"start\" width=\"60px\" formatter=\"blockTimesGridDate\">";
+	$rt .= "<th field=\"start\" width=\"70px\" formatter=\"blockTimesGridDate\">";
 	$rt .= i("Date") . "</th>\n";
-	$rt .= "<th field=\"start\" width=\"54px\" formatter=\"blockTimesGridStart\">";
+	$rt .= "<th field=\"start\" width=\"85px\" formatter=\"blockTimesGridStart\">";
 	$rt .= i("Start") . "</th>\n";
-	$rt .= "<th field=\"end\" width=\"54px\" formatter=\"blockTimesGridEnd\">";
+	$rt .= "<th field=\"end\" width=\"85px\" formatter=\"blockTimesGridEnd\">";
 	$rt .= i("End") . "</th>\n";
 	$rt .= "<th field=\"delbtn\" width=\"60px\">" . i("Skip") . "</th>\n";
 	$rt .= "</tr>\n";
@@ -3133,35 +3133,41 @@
 	if(! $err) {
 		if($type == 'list') {
 			$slots = processInputVar('slots', ARG_STRING);
-			$return['slots'] = explode(',', $slots);
+			if(! preg_match('/^(\d{8}\|\d{2}:\d{2}\|\d{2}:\d{2})(,(\d{8}\|\d{2}:\d{2}\|\d{2}:\d{2}))*$/', $slots)) {
+				$errmsg = i("Invalid time slot submitted.");
+				$err = 1;
+			}
 			$return['times'] = array();
-			$lastdate = array('day' => '', 'ts' => 0);
-			foreach($return['slots'] as $slot) {
-				$tmp = explode('|', $slot);
-				if(count($tmp) != 3) {
-					$errmsg = i("Invalid date/time submitted.");
-					$err = 1;
-					break;
-				}
-				$date = $tmp[0];
-				if(! $err) {
-					$datets = strtotime($date);
-					if($method != 'edit' && $datets < (time() - SECINDAY)) {
-						$errmsg = i("The date must be today or later.");
+			if(! $err) {
+				$return['slots'] = explode(',', $slots);
+				$lastdate = array('day' => '', 'ts' => 0);
+				foreach($return['slots'] as $slot) {
+					$tmp = explode('|', $slot);
+					if(count($tmp) != 3) {
+						$errmsg = i("Invalid date/time submitted.");
 						$err = 1;
 						break;
 					}
+					$date = $tmp[0];
+					if(! $err) {
+						$datets = strtotime($date);
+						if($method != 'edit' && $datets < (time() - SECINDAY)) {
+							$errmsg = i("The date must be today or later.");
+							$err = 1;
+							break;
+						}
+					}
+					$return['times'][] = "{$tmp[1]}|{$tmp[2]}";
+					if($datets > $lastdate['ts']) {
+						$lastdate['ts'] = $datets;
+						$lastdate['day'] = $date;
+					}
 				}
-				$return['times'][] = "{$tmp[1]}|{$tmp[2]}";
-				if($datets > $lastdate['ts']) {
-					$lastdate['ts'] = $datets;
-					$lastdate['day'] = $date;
+				if(! $err) {
+					$expirets = strtotime("{$lastdate['day']} 23:59:59");
+					$return['expiretime'] = unixToDatetime($expirets);
 				}
 			}
-			if(! $err) {
-				$expirets = strtotime("{$lastdate['day']} 23:59:59");
-				$return['expiretime'] = unixToDatetime($expirets);
-			}
 		}
 		if($type == 'weekly' || $type == 'monthly') {
 			$return['startdate'] = processInputVar('startdate', ARG_NUMERIC);
diff --git a/web/.ht-inc/computer.php b/web/.ht-inc/computer.php
index 3a9e117..d1f6ca6 100644
--- a/web/.ht-inc/computer.php
+++ b/web/.ht-inc/computer.php
@@ -1757,6 +1757,11 @@
 		}
 		# add multiple
 		if($return['mode'] == 'add' && $addmode == 'multiple') {
+			# ensure % in hostname
+			if(! preg_match('/%/', $return['name'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Name must contain % when adding multiple computers";
+			}
 			# startnum/endnum
 			if($return['startnum'] < 0 || $return['startnum'] > 255) {
 				$return['error'] = 1;
@@ -4280,27 +4285,33 @@
 
 		$query = "SELECT rs.computerid "
 		       . "FROM request rq, "
-		       .      "reservation rs "
+		       .      "reservation rs, "
+		       .      "state s "
 		       . "WHERE rs.requestid = rq.id AND "
+		       .       "rq.stateid = s.id AND "
 		       .       "rs.computerid IN ($allids) AND "
 		       .       "rq.start <= '$startcheckdt' AND "
-		       .       "rq.end > NOW()";
+		       .       "rq.end > NOW() AND "
+		       .       "s.name != 'complete'";
 		$qh = doQuery($query);
 		while($row = mysqli_fetch_assoc($qh))
 			$fails[] = $row['computerid'];
 
 		$nowids = array_diff($compids, $fails);
-		$allids = implode(',', $nowids);
-		$query = "UPDATE computer "
-		       . "SET provisioningid = $provisioningid "
-		       . "WHERE id in ($allids)";
-		doQuery($query);
+		if(! empty($nowids)) {
+			$allids = implode(',', $nowids);
+			$query = "UPDATE computer "
+			       . "SET provisioningid = $provisioningid "
+			       . "WHERE id in ($allids)";
+			doQuery($query);
+		}
 
 		$resources = getUserResources(array($this->restype . "Admin"), array("administer"));
 		$compdata = $resources[$this->restype];
 
+		$msg = '';
 		if(count($nowids)) {
-			$msg  = "The following computers had their Provisioning Engine set to $provname:<br><br>\n";
+			$msg  .= "The following computers had their Provisioning Engine set to $provname:<br><br>\n";
 			foreach($nowids as $compid)
 				$msg .= "{$compdata[$compid]}<br>\n";
 			$msg .= "<br>";
@@ -4872,9 +4883,11 @@
 		       .        "i.prettyname AS image, "
 		       .        "ir.revision, "
 		       .        "c.hostname AS hostname, "
+		       .        "s.IPaddress, "
 		       .        "mn.hostname AS managementnode, "
 		       .        "l.ending, "
-		       .        "CONCAT(u.unityid, '@', a.name) AS username "
+		       .        "CONCAT(u.unityid, '@', a.name) AS username, "
+		       .        "l.requestid "
 		       . "FROM computer c "
 		       . "LEFT JOIN sublog s ON (c.id = s.computerid) "
 		       . "LEFT JOIN image i ON (s.imageid = i.id) "
@@ -4907,6 +4920,8 @@
 				$msg .= "End: " . prettyDatetime($row['end'], 1) . "<br>";
 			$msg .= "Management Node: {$row['managementnode']}<br>";
 			$msg .= "Ending: {$row['ending']}<br>";
+			$msg .= "Request ID: {$row['requestid']}<br>";
+			$msg .= "IP Address: {$row['IPaddress']}<br>";
 			$msg .= "<hr>";
 			$data[] = array('name' => $row['hostname'], 'msg' => $msg);
 		}
diff --git a/web/.ht-inc/conf-default.php b/web/.ht-inc/conf-default.php
index 50f204b..cff15a3 100644
--- a/web/.ht-inc/conf-default.php
+++ b/web/.ht-inc/conf-default.php
@@ -183,9 +183,9 @@
 		$updateUserFuncArgs[$item['affiliationid']] = $key;
 	}
 	elseif($item['type'] == 'local') {
-		$affilValFunc[$item['affiliationid']] = create_function('', 'return 0;');
-		$addUserFunc[$item['affiliationid']] = create_function('', 'return NULL;');
-		$updateUserFunc[$item['affiliationid']] = create_function('', 'return NULL;');
+		$affilValFunc[$item['affiliationid']] = function() {return 0;};
+		$addUserFunc[$item['affiliationid']] = function() {return NULL;};
+		$updateUserFunc[$item['affiliationid']] = function() {return NULL;};
 	}
 }
 
diff --git a/web/.ht-inc/dashboard.php b/web/.ht-inc/dashboard.php
index 3c2df3f..9018c20 100644
--- a/web/.ht-inc/dashboard.php
+++ b/web/.ht-inc/dashboard.php
@@ -42,7 +42,7 @@
 
 	# -------- left column ---------
 	print "<div id=\"dashleft\">\n";
-	print addWidget('status', 'Current Status');
+	print addWidget('status', 'Current Status', '(Hover for description)');
 	print addWidget('topimages', 'Top 5 Images in Use', '(Reservations &lt; 24 hours long)');
 	print addWidget('toplongimages', 'Top 5 Long Term Images in Use', '(Reservations &gt; 24 hours long)');
 	print addWidget('toppastimages', 'Top 5 Images From Past Day', '(Reservations with a start<br>time within past 24 hours)');
@@ -168,10 +168,11 @@
 function getStatusData() {
 	$affilid = getDashboardAffilID();
 	$data = array();
-	$data[] = array('key' => 'Active Reservations', 'val' => 0);
-	$data[] = array('key' => 'Online Computers', 'val' => 0, 'tooltip' => 'Computers in states available, reserved,<br>reloading, inuse, or timeout');
-	$data[] = array('key' => 'In Use Computers', 'val' => 0, 'tooltip' => 'Computers in inuse state');
-	$data[] = array('key' => 'Failed Computers', 'val' => 0);
+	$data[0] = array('key' => 'Active Reservations', 'val' => 0, 'tooltip' => 'Reservations currently running');
+	$data[1] = array('key' => 'Active Short Reservations', 'val' => 0, 'tooltip' => 'Reservations with a duration < 24 hours');
+	$data[2] = array('key' => 'Online Computers', 'val' => 0, 'tooltip' => 'Computers in states available, reserved,<br>reloading, inuse, or timeout');
+	$data[3] = array('key' => 'In Use Computers', 'val' => 0, 'tooltip' => 'Computers in inuse state');
+	$data[4] = array('key' => 'Failed Computers', 'val' => 0);
 	$reloadid = getUserlistID('vclreload@Local');
 	if($affilid == 0) {
 		$query = "SELECT COUNT(id) "
@@ -196,20 +197,45 @@
 	if($row = mysqli_fetch_row($qh))
 		$data[0]['val'] = $row[0];
 
-	$query = "SELECT COUNT(id) FROM computer WHERE stateid IN (2, 3, 6, 8, 11)";
+	if($affilid == 0) {
+		$query = "SELECT COUNT(id) "
+		       . "FROM request "
+		       . "WHERE userid != $reloadid AND "
+		       .       "stateid NOT IN (1, 5, 10, 12) AND "
+		       .       "start < NOW() AND "
+				 .       "end > NOW() AND "
+		       .       "(UNIX_TIMESTAMP(end) - UNIX_TIMESTAMP(start)) < 86400";
+	}
+	else {
+		$query = "SELECT COUNT(rq.id) "
+		       . "FROM request rq, "
+		       .      "user u "
+		       . "WHERE rq.userid != $reloadid AND "
+		       .       "rq.userid = u.id AND "
+		       .       "u.affiliationid = $affilid AND "
+		       .       "rq.stateid NOT IN (1, 5, 10, 12) AND "
+		       .       "rq.start < NOW() AND "
+				 .       "rq.end > NOW() AND "
+		       .       "(UNIX_TIMESTAMP(end) - UNIX_TIMESTAMP(start)) < 86400";
+	}
 	$qh = doQuery($query, 101);
 	if($row = mysqli_fetch_row($qh))
 		$data[1]['val'] = $row[0];
 
-	$query = "SELECT COUNT(id) FROM computer WHERE stateid = 8";
+	$query = "SELECT COUNT(id) FROM computer WHERE stateid IN (2, 3, 6, 8, 11)";
 	$qh = doQuery($query, 101);
 	if($row = mysqli_fetch_row($qh))
 		$data[2]['val'] = $row[0];
 
-	$query = "SELECT COUNT(id) FROM computer WHERE stateid = 5";
+	$query = "SELECT COUNT(id) FROM computer WHERE stateid = 8";
 	$qh = doQuery($query, 101);
 	if($row = mysqli_fetch_row($qh))
 		$data[3]['val'] = $row[0];
+
+	$query = "SELECT COUNT(id) FROM computer WHERE stateid = 5";
+	$qh = doQuery($query, 101);
+	if($row = mysqli_fetch_row($qh))
+		$data[4]['val'] = $row[0];
 	return $data;
 }
 
@@ -674,6 +700,7 @@
 function getNewReservationData() {
 	$affilid = getDashboardAffilID();
 	$query = "SELECT c.hostname AS computer, "
+	       .        "h.hostname AS vmhost, "
 	       .        "i.prettyname AS image, "
 	       .        "rq.id, "
 	       .        "UNIX_TIMESTAMP(rq.start) AS start, "
@@ -684,6 +711,8 @@
 	       . "FROM request rq "
 	       . "LEFT JOIN reservation rs ON (rs.requestid = rq.id) "
 	       . "LEFT JOIN computer c ON (c.id = rs.computerid) "
+	       . "LEFT JOIN vmhost vh ON (c.vmhostid = vh.id) "
+	       . "LEFT JOIN computer h ON (h.id = vh.computerid) "
 	       . "LEFT JOIN image i ON (i.id = rs.imageid) "
 	       . "LEFT JOIN OS o ON (o.id = i.OSid) "
 	       . "LEFT JOIN state s1 ON (s1.id = rq.stateid) "
@@ -703,6 +732,8 @@
 	while($row = mysqli_fetch_assoc($qh)) {
 		$tmp = explode('.', $row['computer']);
 		$row['computer'] = $tmp[0];
+		$tmp = explode('.', $row['vmhost']);
+		$row['vmhost'] = $tmp[0];
 		$row['start'] = date('D h:i', $row['start']);
 		$tmp = explode('.', $row['managementnode']);
 		$row['managementnode'] = $tmp[0];
diff --git a/web/.ht-inc/doxyfile.xmlrpc b/web/.ht-inc/doxyfile.xmlrpc
index 4880847..f8519e5 100644
--- a/web/.ht-inc/doxyfile.xmlrpc
+++ b/web/.ht-inc/doxyfile.xmlrpc
@@ -1,5 +1,3 @@
-# Doxyfile 1.4.7
-
 #  Licensed to the Apache Software Foundation (ASF) under one or more
 #  contributor license agreements.  See the NOTICE file distributed with
 #  this work for additional information regarding copyright ownership.
@@ -14,10 +12,6 @@
 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
 PROJECT_NAME           = "VCL XML RPC"
 PROJECT_NUMBER         = 
 OUTPUT_DIRECTORY       = xmlrpcdocs/
@@ -53,9 +47,6 @@
 BUILTIN_STL_SUPPORT    = NO
 DISTRIBUTE_GROUP_DOC   = NO
 SUBGROUPING            = NO
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
 EXTRACT_ALL            = NO
 EXTRACT_PRIVATE        = NO
 EXTRACT_STATIC         = NO
@@ -81,9 +72,6 @@
 MAX_INITIALIZER_LINES  = 30
 SHOW_USED_FILES        = NO
 FILE_VERSION_FILTER    = 
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
 QUIET                  = NO
 WARNINGS               = YES
 WARN_IF_UNDOCUMENTED   = YES
@@ -91,9 +79,6 @@
 WARN_NO_PARAMDOC       = NO
 WARN_FORMAT            = "$file:$line: $text"
 WARN_LOGFILE           = 
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
 INPUT                  = .
 FILE_PATTERNS          = xmlrpcWrappers.php
 RECURSIVE              = NO
@@ -107,9 +92,6 @@
 INPUT_FILTER           = 
 FILTER_PATTERNS        = 
 FILTER_SOURCE_FILES    = NO
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
 SOURCE_BROWSER         = NO
 INLINE_SOURCES         = NO
 STRIP_CODE_COMMENTS    = YES
@@ -118,15 +100,9 @@
 REFERENCES_LINK_SOURCE = YES
 USE_HTAGS              = NO
 VERBATIM_HEADERS       = NO
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
 ALPHABETICAL_INDEX     = NO
 COLS_IN_ALPHA_INDEX    = 5
 IGNORE_PREFIX          = 
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
 GENERATE_HTML          = YES
 HTML_OUTPUT            = .
 HTML_FILE_EXTENSION    = .html
@@ -143,9 +119,6 @@
 ENUM_VALUES_PER_LINE   = 4
 GENERATE_TREEVIEW      = NO
 TREEVIEW_WIDTH         = 250
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
 GENERATE_LATEX         = NO
 LATEX_OUTPUT           = latex
 LATEX_CMD_NAME         = latex
@@ -158,44 +131,26 @@
 USE_PDFLATEX           = NO
 LATEX_BATCHMODE        = NO
 LATEX_HIDE_INDICES     = NO
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
 GENERATE_RTF           = NO
 RTF_OUTPUT             = rtf
 COMPACT_RTF            = NO
 RTF_HYPERLINKS         = NO
 RTF_STYLESHEET_FILE    = 
 RTF_EXTENSIONS_FILE    = 
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
 GENERATE_MAN           = NO
 MAN_OUTPUT             = man
 MAN_EXTENSION          = .3
 MAN_LINKS              = NO
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
 GENERATE_XML           = NO
 XML_OUTPUT             = xml
 XML_SCHEMA             = 
 XML_DTD                = 
 XML_PROGRAMLISTING     = YES
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
 GENERATE_AUTOGEN_DEF   = NO
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
 GENERATE_PERLMOD       = NO
 PERLMOD_LATEX          = NO
 PERLMOD_PRETTY         = YES
 PERLMOD_MAKEVAR_PREFIX = 
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor   
-#---------------------------------------------------------------------------
 ENABLE_PREPROCESSING   = YES
 MACRO_EXPANSION        = NO
 EXPAND_ONLY_PREDEF     = NO
@@ -205,17 +160,11 @@
 PREDEFINED             = 
 EXPAND_AS_DEFINED      = 
 SKIP_FUNCTION_MACROS   = YES
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references   
-#---------------------------------------------------------------------------
 TAGFILES               = 
 GENERATE_TAGFILE       = 
 ALLEXTERNALS           = NO
 EXTERNAL_GROUPS        = YES
 PERL_PATH              = /usr/bin/perl
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool   
-#---------------------------------------------------------------------------
 CLASS_DIAGRAMS         = YES
 HIDE_UNDOC_RELATIONS   = YES
 HAVE_DOT               = NO
@@ -238,7 +187,4 @@
 DOT_MULTI_TARGETS      = NO
 GENERATE_LEGEND        = YES
 DOT_CLEANUP            = YES
-#---------------------------------------------------------------------------
-# Configuration::additions related to the search engine   
-#---------------------------------------------------------------------------
 SEARCHENGINE           = NO
diff --git a/web/.ht-inc/help.php b/web/.ht-inc/help.php
index f632f6b..b038d97 100644
--- a/web/.ht-inc/help.php
+++ b/web/.ht-inc/help.php
@@ -130,7 +130,7 @@
 		$testname = stripslashes($name);
 	if(! preg_match('/^([-A-Za-z \']{1,} [-A-Za-z \']{2,})*$/', $testname)) {
 		$submitErr |= NAMEERR;
-		$submitErrMsg[NAMEERR] = "Name can only contain letters, spaces, apostrophes ('), and dashes (-)";
+		$submitErrMsg[NAMEERR] = "Name can only contain letters, spaces, apostrophes ('), and dashes (-). Both first and last name must be specified.";
 	}
 	if(! preg_match('/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i',
 	   $email)) {
@@ -186,9 +186,9 @@
 	$recentrequests = "";
 	foreach($requests as $request) {
 		$thisstart = str_replace('&nbsp;', ' ', 
-				prettyDatetime($request["start"]));
+				prettyDatetime($request["start"], 0, 1));
 		$thisend = str_replace('&nbsp;', ' ', 
-				prettyDatetime($request["end"]));
+				prettyDatetime($request["end"], 0, 1));
 		$recentrequests .= "Image: {$request["prettyimage"]}\n"
 		                .  "Computer: {$computers[$request["computerid"]]["hostname"]}\n"
 		                .  "Start: $thisstart\n"
@@ -202,16 +202,79 @@
 		$message .= "User has no recent reservations\n";
 	}
 
+	# login history
+	$query = "SELECT authmech, "
+	       .        "timestamp, "
+	       .        "passfail, "
+	       .        "remoteIP, "
+	       .        "code "
+	       . "FROM loginlog "
+	       . "WHERE (user = '{$user['unityid']}' OR "
+	       .       "user = '{$user['unityid']}@{$user['affiliation']}') AND "
+	       .       "affiliationid = {$user['affiliationid']} "
+	       . "ORDER BY timestamp DESC "
+	       . "LIMIT 5";
+	$methodlen = strlen(i('Authentication Method'));
+	$timelen = strlen(i('Timestamp'));
+	$resultlen = strlen(i('Result'));
+	$remoteiplen = strlen(i('Remote IP'));
+	$extralen = strlen(i('Extra Info'));
+	if(strlen(i('Pass')) > $resultlen)
+		$resultlen = strlen(i('Pass'));
+	if(strlen(i('Fail')) > $resultlen)
+		$resultlen = strlen(i('Fail'));
+	$qh = doQuery($query);
+	$logins = array();
+	while($row = mysql_fetch_assoc($qh)) {
+		$tmp = prettyDatetime($row['timestamp'], 1, 1);
+		$row['timestamp'] = str_replace('&nbsp;', ' ', $tmp);
+		if($row['passfail'])
+			$row['passfail'] = 'Pass';
+		else
+			$row['passfail'] = 'Fail';
+		if(strlen($row['authmech']) > $methodlen)
+			$methodlen = strlen($row['authmech']);
+		if(strlen($row['timestamp']) > $timelen)
+			$timelen = strlen($row['timestamp']);
+		if(strlen($row['remoteIP']) > $remoteiplen)
+			$remoteiplen = strlen($row['remoteIP']);
+		if(strlen($row['code']) > $extralen)
+			$extralen = strlen($row['code']);
+		$logins[] = $row;
+	}
+	if(count($logins)) {
+		$logins = array_reverse($logins);
+		$message .= "-----------------------------------------------\n";
+		$message .= "User's Login History (up to last 5 attempts):\n\n";
+		$message .= sprintf("%-{$methodlen}s | ", i('Authentication Method'));
+		$message .= sprintf("%-{$timelen}s | ", i('Timestamp'));
+		$message .= sprintf("%-{$resultlen}s | ", i('Result'));
+		$message .= sprintf("%-{$remoteiplen}s | ", i('Remote IP'));
+		$message .= sprintf("%-{$extralen}s\n", i('Extra Info'));
+		foreach($logins as $login) {
+			$message .= sprintf("%-{$methodlen}s | ", $login['authmech']);
+			$message .= sprintf("%-{$timelen}s | ", $login['timestamp']);
+			$message .= sprintf("%-{$resultlen}s | ", $login['passfail']);
+			$message .= sprintf("%-{$remoteiplen}s | ", $login['remoteIP']);
+			$message .= sprintf("%-{$extralen}s\n", $login['code']);
+		}
+	}
+	if(isset($_SERVER['HTTP_USER_AGENT'])) {
+		$message .= "-----------------------------------------------\n";
+		$message .= "User agent: {$_SERVER['HTTP_USER_AGENT']}\n";
+	}
+
 	$indrupal = getContinuationVar('indrupal', 0);
 	if(! $indrupal)
 		print "<H2>VCL Help</H2>\n";
 	$mailParams = "-f" . ENVELOPESENDER;
 	if(get_magic_quotes_gpc())
 		$summary = stripslashes($summary);
-	if(! mail(HELPEMAIL, "$summary", $message,
+	$helpemail = getHelpEmail($user['affiliationid']);
+	if(! mail($helpemail, "$summary", $message,
 	   "From: $from\r\nReply-To: $email\r\n", $mailParams)){
 		print "The Server was unable to send mail at this time. Please e-mail ";
-		print "<a href=\"mailto:" . HELPEMAIL . "\">" . HELPEMAIL . "</a> for ";
+		print "<a href=\"mailto:$helpemail\">$helpemail</a> for ";
 		print "help with your problem.";
 	}
 	else {
@@ -220,4 +283,28 @@
 	}
 }
 
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn getHelpEmail($affil)
+///
+/// \param $affil - id or name of an affiliation
+///
+/// \return email address for $affil or HELPEMAIL from conf.php if $affil does
+/// not have a specific email address set
+///
+/// \brief gets the email address for support for a $affil
+///
+////////////////////////////////////////////////////////////////////////////////
+function getHelpEmail($affil) {
+	if(is_numeric($affil))
+		$field = 'id';
+	else
+		$field = 'name';
+	$query = "SELECT helpaddress FROM affiliation WHERE $field = '$affil'";
+	$qh = doQuery($query);
+	if($row = mysql_fetch_assoc($qh))
+		if($row['helpaddress'] != '')
+			return $row['helpaddress'];
+	return HELPEMAIL;
+}
 ?>
diff --git a/web/.ht-inc/image.php b/web/.ht-inc/image.php
index 8f7bc88..329cec8 100644
--- a/web/.ht-inc/image.php
+++ b/web/.ht-inc/image.php
@@ -366,34 +366,34 @@
 		$h .= "<legend>" . i("Image Description") . "</legend>\n";
 		$h .= i("Description of image (required - users will see this on the <strong>New Reservations</strong> page):");
 		$h .= "<br>\n";
-		$h .= "<textarea dojoType=\"dijit.form.Textarea\" id=\"description\" ";
-		$h .= "style=\"width: 400px; text-align: left;\"></textarea>\n";
+		$h .= "<textarea dojoType=\"dijit.form.Textarea\" id=\"description\">";
+		$h .= "</textarea>\n";
 		$h .= "</fieldset>\n";
 		# usage notes
 		$h .= "<fieldset>\n";
 		$h .= "<legend>" . i("Usage Notes") . "</legend>\n";
 		$msg = i("Optional notes to the user explaining how to use the image (users will see this on the <strong>Connect!</strong> page):");
 		$h .= preg_replace("/(.{1,100}([ \n]|$))/", '\1<br>', $msg);
-		$h .= "<textarea dojoType=\"dijit.form.Textarea\" id=\"usage\" ";
-		$h .= "style=\"width: 400px; text-align: left;\"></textarea>\n";
+		$h .= "<textarea dojoType=\"dijit.form.Textarea\" id=\"usage\">";
+		$h .= "</textarea>\n";
 		$h .= "</fieldset>\n";
 		if($add) {
 			$h .= "<fieldset>\n";
 			$h .= "<legend>" . i("Revision Comments") . "</legend>\n";
 			$msg = i("Notes for yourself and other admins about how the image was setup/installed. These are optional and are not visible to end users.");
 			$h .= preg_replace("/(.{1,80}([ \n]|$))/", '\1<br>', $msg);
-			$h .= "<textarea dojoType=\"dijit.form.Textarea\" id=\"imgcomments\" ";
-			$h .= "style=\"width: 400px; text-align: left;\"></textarea>";
+			$h .= "<textarea dojoType=\"dijit.form.Textarea\" id=\"imgcomments\">";
+			$h .= "</textarea>";
 			$h .= "</fieldset>\n";
 		}
 		# advanced options
 		$h .= "<div dojoType=\"dijit.TitlePane\" title=\"";
 		$h .= i("Advanced Options - leave default values unless you really know what you are doing (click to expand)");
-		$h .= "\" open=\"false\" style=\"width: 460px\" id=\"advancedoptions\" ";
+		$h .= "\" open=\"false\" id=\"advancedoptions\" ";
 		$h .= "onShow=\"delayedEditResize();\" onHide=\"delayedEditResize();\">\n";
 		# RAM
 		$extra = array('smallDelta' => 256, 'largeDelta' => 1024);
-		$h .= labeledFormItem('ram', i('Required RAM'), 'spinner', '{min:512, max:8388607}',
+		$h .= labeledFormItem('ram', i('Required RAM') . ' (MB)', 'spinner', '{min:512, max:8388607}',
 		                      1, 1024, '', '', $extra);
 		# cores
 		$extra = array('smallDelta' => 1, 'largeDelta' => 2);
@@ -1644,7 +1644,7 @@
 		$return["checkuser"] = processInputVar("checkuser", ARG_NUMERIC);
 		$return["rootaccess"] = processInputVar("rootaccess", ARG_NUMERIC);
 		$return["sethostname"] = processInputVar("sethostname", ARG_NUMERIC);
-		$return["maxinitialtime"] = processInputVar("maxinitialtime", ARG_NUMERIC);
+		$return["maxinitialtime"] = processInputVar("maxinitialtime", ARG_NUMERIC, 0);
 		$return["sysprep"] = processInputVar("sysprep", ARG_NUMERIC); # only in add
 		$return["connectmethodids"] = processInputVar("connectmethodids", ARG_STRING); # only in add
 		$return["adauthenabled"] = processInputVar("adauthenabled", ARG_NUMERIC);
@@ -1767,7 +1767,7 @@
 			$extraaddomainid = getContinuationVar('extraaddomainid', 0);
 			$extraaddomainou = getContinuationVar('extraaddomainou', '');
 			if(! array_key_exists($return['addomainid'], $vals) &&
-			   $return['addomainid'] != $extraaddomainid) {
+			   $return['addomainid'] !== $extraaddomainid) {
 				$return['error'] = 1;
 				$errormsg[] = i("Invalid AD Domain submitted");
 			}
diff --git a/web/.ht-inc/privileges.php b/web/.ht-inc/privileges.php
index 165e14b..714b910 100644
--- a/web/.ht-inc/privileges.php
+++ b/web/.ht-inc/privileges.php
@@ -36,8 +36,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 function viewNodes() {
 	global $user;
-	if(! empty($_COOKIE["VCLACTIVENODE"]) &&
-		nodeExists($_COOKIE['VCLACTIVENODE']))
+	if(isset($_COOKIE["VCLACTIVENODE"]) &&
+	   is_numeric($_COOKIE['VCLACTIVENODE']) &&
+	   $_COOKIE['VCLACTIVENODE'] > 0 &&
+	   $_COOKIE['VCLACTIVENODE'] < 16777216 &&
+	   nodeExists($_COOKIE['VCLACTIVENODE']))
 		$activeNode = $_COOKIE["VCLACTIVENODE"];
 	else {
 		$topNodes = getChildNodes();
@@ -1629,6 +1632,12 @@
 		print "      Total: {$times['total']}<br>\n";
 		print "  </TR>\n";
 
+		$maxconcurrent = getMaxOverlap($userdata['id']);
+		print "  <TR>\n";
+		print "    <TH align=right>Max Overlapping Reservations:</TH>\n";
+		print "    <TD>$maxconcurrent</TD>\n";
+		print "  </TR>\n";
+
 		print "  <TR>\n";
 		print "    <TH align=right style=\"vertical-align: top\">Privileges (found somewhere in the tree):</TH>\n";
 		print "    <TD>\n";
@@ -1724,6 +1733,30 @@
 		}
 		print "</div>\n";
 
+		# owned images
+		$ownedimages = array();
+		$query = "SELECT prettyname "
+		       . "FROM image "
+		       . "WHERE ownerid = {$userdata['id']} AND "
+		       .       "deleted = 0 "
+		       . "ORDER BY prettyname";
+		$qh = doQuery($query);
+		while($row = mysqli_fetch_row($qh))
+			$ownedimages[] = $row[0];
+		print "<table>\n";
+		print "  <tr>\n";
+		print "    <th style=\"vertical-align: top;\">Images Owned by User:<th>\n";
+		print "    <td>\n";
+		if(count($ownedimages)) {
+			foreach($ownedimages as $image)
+				print "      $image<br>\n";
+		}
+		else
+			print "      None\n";
+		print "    </td>\n";
+		print "  </tr>\n";
+		print "</table>\n";
+
 		# image access
 		print "<table>\n";
 		print "  <tr>\n";
diff --git a/web/.ht-inc/requests.php b/web/.ht-inc/requests.php
index 565c53c..c836668 100644
--- a/web/.ht-inc/requests.php
+++ b/web/.ht-inc/requests.php
@@ -276,12 +276,14 @@
 					$text .= getViewRequestHTMLitem('openmoreoptions');
 					$text .= getViewRequestHTMLitem('editoption', $editcont);
 					if(array_key_exists($imageid, $resources['image']) && ! $cluster &&            # imageAdmin access, not a cluster,
+					   $requests[$i]['OSinstalltype'] != 'none' &&
 					   ($requests[$i]['currstateid'] == 8 || $requests[$i]['laststateid'] == 8)) { # reservation has been in inuse state
 						$text .= getViewRequestHTMLitem('endcreateoption', $imgcont);
 					}
 					/*else
 						$text .= getViewRequestHTMLitem('endcreateoptiondisable');*/
 					if(array_key_exists($imageid, $resources['image']) && ! $cluster &&
+					   $requests[$i]['OSinstalltype'] != 'none' &&
 					   $requests[$i]['server'] && ($requests[$i]['currstateid'] == 8 ||
 						($requests[$i]['currstateid'] == 14 && $requests[$i]['laststateid'] == 8))) {
 						$chkcdata = $cdata;
@@ -291,7 +293,8 @@
 					}
 					elseif($requests[$i]['server'] && $requests[$i]['currstateid'] == 24)
 						$text .= getViewRequestHTMLitem('checkpointoptiondisable');
-					if($requests[$i]['currstateid'] == 8 ||
+					if((! $cluster && $requests[$i]['OSinstalltype'] != 'none' &&
+					   $requests[$i]['currstateid'] == 8) ||
 					   (! $cluster &&
 					   $requests[$i]['OSinstalltype'] != 'none' &&
 					   $requests[$i]['currstateid'] != 3 &&
@@ -2093,6 +2096,45 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 ///
+/// \fn AJfetchRouterDNS()
+///
+/// \brief get router and dns information for a given IP address
+///
+////////////////////////////////////////////////////////////////////////////////
+function AJfetchRouterDNS() {
+	$data = array('status' => 'none');
+	$page = processInputVar('page', ARG_STRING);
+	if($page != 'deploy') {
+		sendJSON($data);
+		return;
+	}
+	$ipaddr = processInputVar('ipaddr', ARG_STRING);
+	# validate fixed IP address
+	if(! validateIPv4addr($ipaddr)) {
+		sendJSON($data);
+		return;
+	}
+	# validate netmask
+	$netmask = processInputVar('netmask', ARG_STRING);
+	$bnetmask = ip2long($netmask);
+	if(! preg_match('/^[1]+0[^1]+$/', sprintf('%032b', $bnetmask))) {
+		sendJSON($data);
+		return;
+	}
+	$network = ip2long($ipaddr) & $bnetmask;
+	$availnets = getVariable('fixedIPavailnetworks', array());
+	$key = long2ip($network) . "/$netmask";
+	if(array_key_exists($key, $availnets)) {
+		$data = array('status' => 'success',
+		              'page' => $page,
+		              'router' => $availnets[$key]['router'],
+		              'dns' => implode(',', $availnets[$key]['dns']));
+	}
+	sendJSON($data);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
 /// \fn AJshowRequestSuggestedTimes()
 ///
 /// \brief builds html to display list of available times the selected image
@@ -2359,7 +2401,8 @@
 		return;
 	}
 	elseif($availablerc == -3) {
-		$msg = i("The IP or MAC address you specified overlaps with another reservation using the same IP or MAC address you specified. Please use a different IP or MAC or select a different time to deploy the server.");
+		#$msg = i("The IP or MAC address you specified overlaps with another reservation using the same IP or MAC address you specified. Please use a different IP or MAC or select a different time to deploy the server.");
+		$msg = i("The IP address you specified overlaps with another reservation using the same IP address. Please use a different IP address or select a different time to deploy the server.");
 		$data = array('err' => 1,
 		              'errmsg' => $msg);
 		sendJSON($data);
@@ -3859,7 +3902,8 @@
 			$msgip = " ($ip)";
 		if(! empty($mac))
 			$msgmac = " ($mac)";
-		$h .= sprintf(i("The reserved IP (%s) or MAC address (%s) conflicts with another reservation using the same IP or MAC address. Please select a different time to use the image."), $msgip, $msgmac);
+		#$h .= sprintf(i("The reserved IP (%s) or MAC address (%s) conflicts with another reservation using the same IP or MAC address. Please select a different time to use the image."), $msgip, $msgmac);
+		$h .= sprintf(i("The reserved IP address (%s) conflicts with another reservation using the same IP address. Please select a different time to use the image."), $msgip);
 		$h = preg_replace("/(.{1,60}([ \n]|$))/", '\1<br>', $h);
 		$cdata = getContinuationVar();
 		$cont = addContinuationsEntry('AJsubmitEditRequest', $cdata, SECINDAY, 1, 0);
@@ -5040,10 +5084,14 @@
 function AJsetImageProduction() {
 	$requestid = getContinuationVar('requestid');
 	$data = getRequestInfo($requestid);
-	foreach($data["reservations"] as $res) {
-		if($res["forcheckout"]) {
-			$prettyimage = $res["prettyimage"];
-			break;
+	if($data['forimaging'])
+		$prettyimage = $data['reservations'][0]['prettyimage'];
+	else {
+		foreach($data["reservations"] as $res) {
+			if($res["forcheckout"]) {
+				$prettyimage = $res["prettyimage"];
+				break;
+			}
 		}
 	}
 	$title = "<big><strong>" . i("Change Test Image to Production") . "</strong></big><br><br>\n";
@@ -5068,10 +5116,14 @@
 function AJsubmitSetImageProduction() {
 	$requestid = getContinuationVar('requestid');
 	$data = getRequestInfo($requestid);
-	foreach($data["reservations"] as $res) {
-		if($res["forcheckout"]) {
-			$prettyimage = $res["prettyimage"];
-			break;
+	if($data['forimaging'])
+		$prettyimage = $data['reservations'][0]['prettyimage'];
+	else {
+		foreach($data["reservations"] as $res) {
+			if($res["forcheckout"]) {
+				$prettyimage = $res["prettyimage"];
+				break;
+			}
 		}
 	}
 	$query = "UPDATE request SET stateid = 17 WHERE id = $requestid";
diff --git a/web/.ht-inc/resource.php b/web/.ht-inc/resource.php
index cc55d09..04a5e10 100644
--- a/web/.ht-inc/resource.php
+++ b/web/.ht-inc/resource.php
@@ -1731,6 +1731,11 @@
 	               'baserevisionid' => $revid,
 	               'checkpoint' => $checkpoint,
 	               'add' => 1);
+	$cdata['addomainvals'] = array();
+	if(in_array("addomainAdmin", $user["privileges"])) {
+		$vals = getUserResources(array('addomainAdmin'), array("manageGroup"));
+		$cdata['addomainvals'] = $vals['addomain'];
+	}
 	$cont = addContinuationsEntry('AJsaveResource', $cdata, SECINDAY, 0);
 	$arr = array('newcont' => $cont,
 	             'enableupdate' => 0,
diff --git a/web/.ht-inc/serverprofiles.php b/web/.ht-inc/serverprofiles.php
index 2de4826..9d9ad37 100644
--- a/web/.ht-inc/serverprofiles.php
+++ b/web/.ht-inc/serverprofiles.php
@@ -1138,43 +1138,4 @@
 	sendJSON($arr);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-///
-/// \fn AJfetchRouterDNS()
-///
-/// \brief get router and dns information for a given IP address
-///
-////////////////////////////////////////////////////////////////////////////////
-function AJfetchRouterDNS() {
-	$data = array('status' => 'none');
-	$page = processInputVar('page', ARG_STRING);
-	if($page != 'deploy' && $page != 'profile') {
-		sendJSON($data);
-		return;
-	}
-	$ipaddr = processInputVar('ipaddr', ARG_STRING);
-	# validate fixed IP address
-	if(! validateIPv4addr($ipaddr)) {
-		sendJSON($data);
-		return;
-	}
-	# validate netmask
-	$netmask = processInputVar('netmask', ARG_STRING);
-	$bnetmask = ip2long($netmask);
-	if(! preg_match('/^[1]+0[^1]+$/', sprintf('%032b', $bnetmask))) {
-		sendJSON($data);
-		return;
-	}
-	$network = ip2long($ipaddr) & $bnetmask;
-	$availnets = getVariable('fixedIPavailnetworks', array());
-	$key = long2ip($network) . "/$netmask";
-	if(array_key_exists($key, $availnets)) {
-		$data = array('status' => 'success',
-		              'page' => $page,
-		              'router' => $availnets[$key]['router'],
-		              'dns' => implode(',', $availnets[$key]['dns']));
-	}
-	sendJSON($data);
-}
-
 ?>
diff --git a/web/.ht-inc/siteconfig.php b/web/.ht-inc/siteconfig.php
index 27d6e0f..bda65f2 100644
--- a/web/.ht-inc/siteconfig.php
+++ b/web/.ht-inc/siteconfig.php
@@ -3115,7 +3115,7 @@
 	function __construct($globalopts) {
 		$this->basecdata['obj'] = $this;
 		$this->name = _('Messages');
-		$this->desc = sprintf(_("This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in squeare brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."), "http://vcl.apache.org/docs/message_substitutions.html");
+		$this->desc = sprintf(_("This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in square brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."), "http://vcl.apache.org/docs/message_substitutions.html");
 		$this->affils = getAffiliations();
 		$this->units = array();
 		$this->basekeys = array();
diff --git a/web/.ht-inc/states.php b/web/.ht-inc/states.php
index ae4227c..2e7cb06 100644
--- a/web/.ht-inc/states.php
+++ b/web/.ht-inc/states.php
@@ -150,8 +150,8 @@
                         'AJremGroupFromProfile',
                         'AJaddProfileToGroup',
                         'AJremProfileFromGroup',
-                        'AJserverProfileStoreData',
-                        'AJfetchRouterDNS',*/
+                        'AJserverProfileStoreData',*/
+                        'AJfetchRouterDNS',
                         'AJconfirmDeleteRequest',
                         'AJsubmitDeleteRequest',
                         'AJconfirmRemoveRequest',
@@ -257,6 +257,7 @@
 $actions['mode']['sendRDPfile'] = "sendRDPfile";
 $actions['mode']['AJcheckConnectTimeout'] = "AJcheckConnectTimeout";
 $actions['mode']['AJpreviewClickThrough'] = "AJpreviewClickThrough";
+$actions['mode']['AJfetchRouterDNS'] = "AJfetchRouterDNS";
 #$actions['mode']['connectMindterm'] = "connectMindterm";
 #$actions['mode']['connectRDPapplet'] = "connectRDPapplet";
 $actions['pages']['AJnewRequest'] = "reservations";
@@ -281,6 +282,7 @@
 $actions['pages']['sendRDPfile'] = "reservations";
 $actions['pages']['AJcheckConnectTimeout'] = "reservations";
 $actions['pages']['AJpreviewClickThrough'] = "reservations";
+$actions['pages']['AJfetchRouterDNS'] = "reservations";
 #$actions['pages']['connectMindterm'] = "currentReservations";
 #$actions['pages']['connectRDPapplet'] = "currentReservations";
 
@@ -386,7 +388,6 @@
 $actions['mode']['AJaddProfileToGroup'] = "AJaddProfileToGroup";
 $actions['mode']['AJremProfileFromGroup'] = "AJremProfileFromGroup";
 $actions['mode']['AJserverProfileStoreData'] = "AJserverProfileStoreData";
-$actions['mode']['AJfetchRouterDNS'] = "AJfetchRouterDNS";
 $actions['pages']['serverProfiles'] = "serverProfiles";
 $actions['pages']['AJsaveServerProfile'] = "serverProfiles";
 $actions['pages']['AJserverProfileData'] = "serverProfiles";
@@ -397,8 +398,7 @@
 $actions['pages']['AJremGroupFromProfile'] = "serverProfiles";
 $actions['pages']['AJaddProfileToGroup'] = "serverProfiles";
 $actions['pages']['AJremProfileFromGroup'] = "serverProfiles";
-$actions['pages']['AJserverProfileStoreData'] = "serverProfiles";
-$actions['pages']['AJfetchRouterDNS'] = "serverProfiles";*/
+$actions['pages']['AJserverProfileStoreData'] = "serverProfiles";*/
 
 # time table
 # TODO a few of these belong to new reservation
diff --git a/web/.ht-inc/statistics.php b/web/.ht-inc/statistics.php
index f30998f..9d749fe 100644
--- a/web/.ht-inc/statistics.php
+++ b/web/.ht-inc/statistics.php
@@ -213,7 +213,8 @@
 		       .        "l.wasavailable, "
 		       .        "l.ending, "
 		       .        "i.prettyname, "
-		       .        "o.prettyname AS OS "
+		       .        "o.prettyname AS OS, "
+		       .        "o.type AS OStype "
 		       . "FROM log l, "
 		       .      "image i, "
 		       .      "user u, "
@@ -234,7 +235,8 @@
 		       .        "l.wasavailable, "
 		       .        "l.ending, "
 		       .        "i.prettyname, "
-		       .        "o.prettyname AS OS "
+		       .        "o.prettyname AS OS, "
+		       .        "o.type AS OStype "
 		       . "FROM image i, "
 		       .      "user u, "
 		       .      "OS o, "
@@ -282,6 +284,7 @@
 	$imageload6to8 = array();
 	$imageload8more = array();
 	$imagefails = array();
+	$imageostype = array();
 	$lengths = array("30min" => 0,
 	                 "1hour" => 0,
 	                 "2hours" => 0,
@@ -301,6 +304,8 @@
 			$imageload6to8[$row["prettyname"]] = 0;
 		if(! array_key_exists($row["prettyname"], $imageload8more))
 			$imageload8more[$row["prettyname"]] = 0;
+		if(! isset($imageostype[$row["prettyname"]]))
+			$imageostype[$row["prettyname"]] = ucfirst($row['OStype']);
 
 		# notavailable
 		if($row["wasavailable"] == 0) {
@@ -452,6 +457,7 @@
 	print "    <TH>" . i("6-8 min wait") . "</TH>\n";
 	print "    <TH>" . i("&gt;= 8 min wait") . "</TH>\n";
 	print "    <TH>" . i("Failures") . "</TH>\n";
+	print "    <TH>" . i("OS Type") . "</TH>\n";
 	print "  </TR>\n";
 	foreach($imagecount as $key => $value) {
 		print "  <TR>\n";
@@ -477,6 +483,7 @@
 		}
 		else
 			print "    <TD align=center>{$imagefails[$key]}</TD>\n";
+		print "    <TD align=center>{$imageostype[$key]}</TD>\n";
 		print "  </TR>\n";
 	}
 	print "</TABLE>\n";
diff --git a/web/.ht-inc/utils.php b/web/.ht-inc/utils.php
index 74c7c8c..aaf3cbd 100644
--- a/web/.ht-inc/utils.php
+++ b/web/.ht-inc/utils.php
@@ -56,8 +56,8 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function initGlobals() {
-	global $mode, $user, $remoteIP, $authed, $oldmode, $semid;
-	global $days, $phpVer, $keys, $pemkey, $AUTHERROR;
+	global $mode, $user, $remoteIP, $authed, $oldmode;
+	global $days, $phpVer, $keys, $pemkey, $submitErr, $submitErrMsg;
 	global $passwdArray, $skin, $contdata, $lastmode, $inContinuation;
 	global $ERRORS, $actions;
 	global $affilValFunc, $addUserFunc, $updateUserFunc, $addUserFuncArgs;
@@ -87,7 +87,7 @@
 
 	if(function_exists('openssl_encrypt')) {
 		define('USE_PHPSECLIB', 0);
-		$crytpkey = base64_decode($cryptkey);
+		$cryptkey = base64_decode($cryptkey);
 	}
 	else {
 		define('USE_PHPSECLIB', 1);
@@ -139,7 +139,10 @@
 	                     's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3',
 	                     '4', '5', '6', '7', '8', '9', '0');
 
-	if(array_key_exists('VCLAUTH', $_COOKIE) || $mode == 'submitLogin') {
+	if(isset($_COOKIE['VCLAUTH']) ||
+	   $mode == 'submitLogin' ||
+	   $mode == 'selectauth' ||
+	   $mode == 'main') {
 		// open keys
 		$fp = fopen(".ht-inc/keys.pem", "r");
 		$key = fread($fp, 8192);
@@ -279,9 +282,9 @@
 		$id = $row['id'];
 		if(! array_key_exists($id, $affilValFunc)) {
 			if(ALLOWADDSHIBUSERS)
-				$affilValFunc[$id] = create_function('', 'return 1;');
+				$affilValFunc[$id] = function() {return 1;};
 			else
-				$affilValFunc[$id] = create_function('', 'return 0;');
+				$affilValFunc[$id] = function() {return 0;};
 		}
 		if(! array_key_exists($id, $addUserFunc)) {
 			if(ALLOWADDSHIBUSERS) {
@@ -289,10 +292,10 @@
 				$addUserFuncArgs[$id] = $id;
 			}
 			else
-				$addUserFunc[$id] = create_function('', 'return 0;');
+				$addUserFunc[$id] = function() {return 0;};
 		}
 		if(! array_key_exists($id, $updateUserFunc))
-			$updateUserFunc[$id] = create_function('', 'return NULL;');
+			$updateUserFunc[$id] = function() {return NULL;};
 	}
 
 	# include appropriate files
@@ -382,8 +385,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 function checkAccess() {
 	global $mode, $user, $actionFunction, $authMechs;
-	global $itecsauthkey, $ENABLE_ITECSAUTH, $actions, $noHTMLwrappers;
-	global $inContinuation, $docreaders, $apiValidateFunc;
+	global $itecsauthkey, $ENABLE_ITECSAUTH, $actions;
+	global $inContinuation, $apiValidateFunc;
 	if($mode == 'xmlrpccall') {
 		// double check for SSL
 		if(! isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
@@ -391,6 +394,11 @@
 			dbDisconnect();
 			exit;
 		}
+		if(! isset($_SERVER['HTTP_X_USER'])) {
+			printXMLRPCerror(3);   # access denied
+			dbDisconnect();
+			exit;
+		}
 		$xmluser = processInputData($_SERVER['HTTP_X_USER'], ARG_STRING, 1);
 		if(! $user = getUserInfo($xmluser)) {
 			// if first call to getUserInfo fails, try calling with $noupdate set
@@ -769,7 +777,8 @@
 			# check to see if end time has been reached
 			$fh = fopen($file, 'r');
 			$msg = '';
-			while($line = fgetss($fh)) {
+			while($line = fgets($fh)) {
+			    $line = strip_tags($line);
 				if(preg_match("/^END=([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})$/", $line, $matches)) {
 					$tmp = "{$matches[1]}-{$matches[2]}-{$matches[3]} {$matches[4]}:{$matches[5]}:00";
 					$end = datetimeToUnix($tmp);
@@ -969,7 +978,7 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function main() {
-	global $user, $authed, $mode;
+	global $user, $authed;
 	print "<H2>" . i("Welcome to the Virtual Computing Lab") . "</H2>\n";
 	if($authed) {
 		if(! empty($user['lastname']) && ! empty($user['preferredname']))
@@ -1023,10 +1032,10 @@
 		xmlRPCabort($errcode, $query);
 	if(ONLINEDEBUG && checkUserHasPerm('View Debug Information')) {
 		if($errcode >= 100 && $errcode < 400) {
-			print "<font color=red>" . mysqli_error($mysqli_link_vcl) . "</font><br>\n";
+			print "<span class=\"rederrormsg\">" . mysqli_error($mysqli_link_vcl) . "</span><br>\n";
 			error_log(mysqli_error($mysqli_link_vcl));
 			if($ENABLE_ITECSAUTH) {
-				print "<font color=red>" . mysqli_error($mysqli_link_acct) . "</font><br>\n";
+				print "<span class=\"rederrormsg\">" . mysqli_error($mysqli_link_acct) . "</span><br>\n";
 				error_log(mysqli_error($mysqli_link_acct));
 			}
 			print "$query<br>\n";
@@ -1453,7 +1462,8 @@
 	       . "WHERE i.userid = u.id AND ";
 	if(! $includedeleted)
 		$query .=   "i.deleted = 0 AND ";
-	$query .=      "u.affiliationid = a.id";
+	$query .=      "u.affiliationid = a.id "
+	       . "ORDER BY i.imageid, i.revision";
 	$qh = doQuery($query, 101);
 	while($row = mysqli_fetch_assoc($qh)) {
 		$id = $row['imageid'];
@@ -2099,7 +2109,6 @@
 		$bygroup = 1;
 	if(! $userid)
 		$userid = $user["id"];
-	$return = array();
 
 	$nodeprivs = array();
 	$startnodes = array();
@@ -2861,7 +2870,7 @@
 	}
 	else
 		$padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
-	$savehdlr = set_error_handler(create_function('', ''));
+	$savehdlr = set_error_handler(function() {});
 	if(@openssl_public_encrypt($secret, $encdata, $cryptkey, $padding)) {
 		set_error_handler($savehdlr);
 		$b64data = base64_encode($encdata);
@@ -2891,7 +2900,7 @@
 	$file .= "/.ht-inc/cryptkey/private.pem";
 	$prikey = openssl_pkey_get_private("file://$file", $pemkey);
 	# decrypt secret using private key
-	$savehdlr = set_error_handler(create_function('', ''));
+	$savehdlr = set_error_handler(function() {});
 	if(ASYMOPT == 'OAEP')
 		$padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
 	# OAEP currently only supported padding option
@@ -4258,7 +4267,6 @@
 			return NULL;
 	}
 
-	$user = array();
 	$query = "SELECT u.unityid AS unityid, "
 	       .        "u.affiliationid, "
 	       .        "af.name AS affiliation, "
@@ -4496,7 +4504,6 @@
 		$qh = doQuery($query, 101);
 		if($row = mysqli_fetch_assoc($qh)) {
 			$id = $row['unityid'];
-			$type = 'loginid';
 			$affilid = $row['affiliationid'];
 		}
 		else
@@ -5085,6 +5092,8 @@
 			while($row = mysqli_fetch_assoc($qh))
 				$newcompids[] = $row['id'];
 			$computerids = $newcompids;
+			if(empty($computerids) && empty($blockids))
+				return debugIsAvailable(0, 23, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual);
 		}
 
 		# check for use of specified IP address, have to wait until here
@@ -5106,7 +5115,7 @@
 			$qh = doQuery($query);
 			if(mysqli_num_rows($qh)) {
 				if($now)
-					return debugIsAvailable(-4, 18, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual);
+					return debugIsAvailable(-4, 24, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual);
 				$requestInfo['ipwarning'] = 1;
 			}
 			$query = "SELECT id "
@@ -5208,7 +5217,7 @@
 function debugIsAvailable($rc, $loc, $start, $end, $imagerevisionid,
 	                       $compids=array(), $currentids=array(),
 	                       $blockids=array(), $failedids=array(), $virtual='') {
-	global $user, $mode, $requestInfo;
+	global $mode, $requestInfo;
 	$debug = getContinuationVar('debug', 0);
 	if(! $debug ||
 	   $mode != 'AJupdateWaitTime' ||
@@ -5266,9 +5275,6 @@
 		case "13":
 			$msg = "no computers available (after virtual host resource checks/before performing overlapping IP address check)";
 			break;
-		case "18":
-			$msg = "requested IP address in use by another computer";
-			break;
 		case "22":
 			$msg = "at least 2 computers have the requested IP address assigned to them";
 			break;
@@ -5278,6 +5284,12 @@
 		case "12":
 			$msg = "successfully found a computer (id: {$requestInfo['computers'][0]})";
 			break;
+		case "23":
+			$msg = "no computers available after performing VM host check";
+			break;
+		case "24":
+			$msg = "requested IP address in use by another computer";
+			break;
 	}
 	print "console.log('$msg');";
 	return $rc;
@@ -5412,7 +5424,6 @@
 function allocComputer($blockids, $currentids, $computerids, $start, $end,
                        $nowfuture, $imageid, $imagerevisionid, $holdcomps,
                        $requestid) {
-	global $requestInfo;
 	$ret = array();
 	if(SCHEDULER_ALLOCATE_RANDOM_COMPUTER) {
 		shuffle($blockids);
@@ -5696,7 +5707,6 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function checkOverlap($start, $end, $max, $requestid=0) {
-	global $user;
 	$requests = getUserRequests("all");
 	$count = 0;
 	if($max > 0)
@@ -5875,7 +5885,7 @@
 	       .       "'$endstamp', "
 	       .       "NOW(), "
 	       .       "$checkuser)";
-	$qh = doQuery($query, 136);
+	doQuery($query, 136);
 
 	$qh = doQuery("SELECT LAST_INSERT_ID() FROM request", 134);
 	if(! $row = mysqli_fetch_row($qh)) {
@@ -6037,7 +6047,6 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function findManagementNode($compid, $start, $nowfuture) {
-	global $HTMLheader;
 	$allmgmtnodes = array_keys(getManagementNodes($nowfuture));
 	$mapped = getMappedResources($compid, "computer", "managementnode");
 	$usablemgmtnodes = array_intersect($allmgmtnodes, $mapped);
@@ -6359,7 +6368,7 @@
 				       . "WHERE id = {$request['id']}";
 			}
 		}
-		$qh = doQuery($query, 150);
+		doQuery($query, 150);
 
 		addChangeLogEntry($request["logid"], NULL, unixToDatetime($now), NULL,
 		                  NULL, "released");
@@ -6402,7 +6411,7 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function moveReservationsOffComputer($compid=0, $count=0) {
-	global $requestInfo, $user;
+	global $requestInfo;
 	$resInfo = array();
 	$checkstart = unixToDatetime(time() + 180);
 	if($compid == 0) {
@@ -7183,29 +7192,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 ///
-/// \fn getDepartmentName($id)
-///
-/// \param $id - id for a department in the department table
-///
-/// \return if found, department name; if not, 0
-///
-/// \brief looks up the name field corresponding to $id in the department table
-/// and returns it
-///
-////////////////////////////////////////////////////////////////////////////////
-function getDepartmentName($id) {
-	$query = "SELECT name FROM department WHERE id = '$id'";
-	$qh = doQuery($query, 101);
-	if($row = mysqli_fetch_row($qh)) {
-		return $row[0];
-	}
-	else {
-		return 0;
-	}
-}
-
-////////////////////////////////////////////////////////////////////////////////
-///
 /// \fn getImageId($image)
 ///
 /// \param $image - name of an image (must match name (not prettyname) in the
@@ -7580,11 +7566,9 @@
 	while($row = mysqli_fetch_assoc($qh))
 		$compgroups[] = $row['resourcegroupid'];
 	$mngrps = array();
-	foreach($compgroups as $grpid) {
-		$mngrpset = getResourceMapping('managementnode', 'computer', '', implode(',', $compgroups));
-		foreach($mngrpset as $mngrpid => $compgrpset)
-			$mngrps[$mngrpid] = 1;
-	}
+	$mngrpset = getResourceMapping('managementnode', 'computer', '', implode(',', $compgroups));
+	foreach($mngrpset as $mngrpid => $compgrpset)
+		$mngrps[$mngrpid] = 1;
 	$mngrpnames = array();
 	foreach(array_keys($mngrps) as $mnid) {
 		$mngrpnames[] = getResourceGroupName($mnid);
@@ -8562,6 +8546,7 @@
 	       .      "reservation rs, "
 	       .      "image i, "
 	       .      "state s, "
+	       .      "state rqs, "
 	       .      "computer c, "
 	       .      "provisioningOSinstalltype poi, "
 	       .      "OSinstalltype oi, "
@@ -8569,6 +8554,8 @@
 	       . "WHERE rs.requestid = rq.id AND "
 	       .       "(rq.start > '$startdt' OR "
 	       .        "(DATE_ADD(rq.end, INTERVAL 15 MINUTE) > '$startdt' AND rq.start <= '$startdt')) AND "
+	       .       "rq.stateid = rqs.id AND "
+	       .       "rqs.name NOT IN ('failed', 'complete', 'reload') AND "
 	       .       "rs.computerid IN ($incompids) AND "
 	       .       "i.id = $imageid AND "
 	       .       "c.id = rs.computerid AND "
@@ -9445,7 +9432,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 ///
-/// \fn getReservationNATports($resid)
+/// \fn getNATports($resid)
 ///
 /// \param $resid - id of a reservation
 ///
@@ -13115,7 +13102,7 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function sendHeaders() {
-	global $mode, $user, $authed, $oldmode, $actionFunction;
+	global $mode, $user, $authed, $actionFunction;
 	global $shibauthed, $authFuncs;
 	if(! $authed && $mode == "auth") {
 		header("Location: " . BASEURL . SCRIPT . "?mode=selectauth");
@@ -13210,8 +13197,8 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function printHTMLHeader() {
-	global $mode, $user, $authed, $oldmode, $HTMLheader, $contdata;
-	global $printedHTMLheader, $docreaders, $noHTMLwrappers, $actions;
+	global $mode, $user, $authed, $HTMLheader, $contdata;
+	global $printedHTMLheader, $noHTMLwrappers;
 	if($printedHTMLheader)
 		return;
 	$refresh = 0;
@@ -13787,23 +13774,6 @@
 			                      'dijit.form.ValidationTextBox',
 			                      'dijit.layout.TabContainer');
 			break;
-		# TODO clean up
-		/*case 'serverProfiles':
-			$filename = 'vclServerProfiles.js';
-			$dojoRequires = array('dojo.parser',
-			                      'dijit.Dialog',
-			                      'dijit.form.Button',
-			                      'dijit.form.FilteringSelect',
-			                      'dijit.form.Select',
-			                      'dijit.form.TextBox',
-			                      'dijit.form.ValidationTextBox',
-			                      'dijit.form.CheckBox',
-			                      'dijit.form.Textarea',
-			                      'dijit.layout.ContentPane',
-			                      'dijit.layout.TabContainer',
-			                      'dojox.string.sprintf',
-			                      'dojo.data.ItemFileWriteStore');
-			break;*/
 		/*case 'testDojoREST':
 			$filename = '';
 			$dojoRequires = array('dojo.parser',
@@ -13855,8 +13825,6 @@
 			$rt .= "      testJS();\n";
 			$rt .= "      document.onmousemove = updateMouseXY;\n";
 			$rt .= "      showScriptOnly();\n";
-			/*$cont = addContinuationsEntry('AJserverProfileStoreData', array(), 120, 1, 0);
-			$rt .= "   populateProfileStore('$cont');\n";*/
 			$rt .= "   });\n";
 			if($refresh)
 				$rt .= "   refresh_timer = setTimeout(resRefresh, 12000);\n";
diff --git a/web/.ht-inc/vm.php b/web/.ht-inc/vm.php
index 90c96a5..df10b43 100644
--- a/web/.ht-inc/vm.php
+++ b/web/.ht-inc/vm.php
@@ -437,9 +437,7 @@
 	$currvms = array_merge($currvms);
 	$noaccess = array_merge($noaccess);
 	$freevms = array_merge($freevms);
-	$cont = addContinuationsEntry('AJchangeVMprofile', array(), 3600, 1, 0);
 	$arr = array('profile' => $data[$vmhostid]['vmprofiledata'],
-	             'continuation' => $cont,
 	             'allvms' => $allvms,
 	             'currvms' => $currvms,
 	             'noaccess' => $noaccess,
@@ -516,6 +514,10 @@
 	$fails = array();
 
 	$vmlistids = processInputVar('listids', ARG_STRING);
+	if(! preg_match('/^(\d+)(,\d+)*$/', $vmlistids)) {
+		sendJSON(array('failed' => 'invaliddata'));
+		return;
+	}
 	$vmids = explode(',', $vmlistids);
 
 	# get data about submitted vms to add
@@ -583,6 +585,10 @@
 
 	$fails = array();
 	$vmlistids = processInputVar('listids', ARG_STRING);
+	if(! preg_match('/^(\d+)(,\d+)*$/', $vmlistids)) {
+		sendJSON(array('failed' => 'invaliddata'));
+		return;
+	}
 	$vmids = explode(',', $vmlistids);
 	$rems = array();
 	$checks = array();
@@ -718,6 +724,10 @@
 
 	$fails = array();
 	$requestids = processInputVar('listids', ARG_STRING);
+	if(! preg_match('/^(\d+)(,\d+)*$/', $requestids)) {
+		sendJSON(array('failed' => 'invaliddata'));
+		return;
+	}
 	$now = time();
 	$msg = 'FAIL';
 	foreach(explode(',', $requestids) AS $reqid) {
@@ -944,10 +954,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 function AJnewProfile() {
 	$newprofile = processInputVar('newname', ARG_STRING);
-	if(get_magic_quotes_gpc()) {
+	if(get_magic_quotes_gpc())
 		$newprofile = stripslashes($newprofile);
-		$newprofile = vcl_mysql_escape_string($newprofile);
-	}
+	$newprofile = vcl_mysql_escape_string($newprofile);
 	$query = "SELECT id FROM vmprofile WHERE profilename = '$newprofile'";
 	$qh = doQuery($query, 101);
 	if($row = mysqli_fetch_assoc($qh)) {
diff --git a/web/.ht-inc/xmlrpcWrappers.php b/web/.ht-inc/xmlrpcWrappers.php
index 33b1587..750000e 100644
--- a/web/.ht-inc/xmlrpcWrappers.php
+++ b/web/.ht-inc/xmlrpcWrappers.php
@@ -19,9 +19,9 @@
 /**
  * \file
  * The functions listed here are for making VCL requests from other applications.
- * They are implemented according to the XML RPC spec defined at 
+ * They are implemented according to the XML RPC spec defined at
  * http://www.xmlrpc.com/ \n
- * There is one function called \b XMLRPCtest() that can be used during 
+ * There is one function called \b XMLRPCtest() that can be used during
  * initial development to get started without actually making a request.\n
  * \n
  * The URL you will use to submit RPC calls is the URL for your VCL site
@@ -171,7 +171,7 @@
 	$length = processInputData($length, ARG_NUMERIC);
 	#$foruser = processInputData($foruser, ARG_STRING, 1);
 
-	// make sure user didn't submit a request for an image he 
+	// make sure user didn't submit a request for an image he
 	// doesn't have access to
 	$resources = getUserResources(array("imageAdmin", "imageCheckOut"));
 	$validImageids = array_keys($resources['image']);
@@ -233,7 +233,7 @@
 	$revisionid = getProductionRevisionid($imageid);
 	$rc = isAvailable($images, $imageid, $revisionid, $start, $end, 1);
 	if($rc < 1) {
-		addLogEntry($nowfuture, unixToDatetime($start), 
+		addLogEntry($nowfuture, unixToDatetime($start),
 		            unixToDatetime($end), 0, $imageid);
 		return array('status' => 'notavailable');
 	}
@@ -354,7 +354,7 @@
 	$revisionid = getProductionRevisionid($imageid);
 	$rc = isAvailable($images, $imageid, $revisionid, $start, $end, 1);
 	if($rc < 1) {
-		addLogEntry($nowfuture, unixToDatetime($start), 
+		addLogEntry($nowfuture, unixToDatetime($start),
 		            unixToDatetime($end), 0, $imageid);
 		return array('status' => 'notavailable');
 	}
@@ -387,7 +387,7 @@
 /// \param $foruser - (optional) login to be used when setting up the account
 /// on the reserved machine - CURRENTLY, THIS IS UNSUPPORTED
 /// \param $name - (optional) name for reservation
-/// \param $userdata - (optional) text that will be placed in 
+/// \param $userdata - (optional) text that will be placed in
 /// /root/.vclcontrol/post_reserve_userdata on the reserved node
 ///
 /// \return an array with at least one index named '\b status' which will have
@@ -562,7 +562,7 @@
 	$rc = isAvailable($images, $imageid, $revisionid, $start, $end,
 	                  1, 0, 0, 0, 0, $ipaddr, $macaddr);
 	if($rc < 1) {
-		addLogEntry($nowfuture, unixToDatetime($start), 
+		addLogEntry($nowfuture, unixToDatetime($start),
 		            unixToDatetime($end), 0, $imageid);
 		return array('status' => 'notavailable');
 	}
@@ -851,23 +851,23 @@
 		$portdata = array();
 		foreach($connectMethods as $key => $cm) {
 			$connecttext = $cm["connecttext"];
-			$connecttext = preg_replace("/#userid#/", $thisuser, $connecttext); 
-			$connecttext = preg_replace("/#password#/", $passwd, $connecttext); 
-			$connecttext = preg_replace("/#connectIP#/", $serverIP, $connecttext); 
+			$connecttext = preg_replace("/#userid#/", $thisuser, $connecttext);
+			$connecttext = preg_replace("/#password#/", $passwd, $connecttext);
+			$connecttext = preg_replace("/#connectIP#/", $serverIP, $connecttext);
 			foreach($cm['ports'] as $port) {
 				if(! empty($natports) && array_key_exists($port['key'], $natports[$key])) {
-					$connecttext = preg_replace("/{$port['key']}/", $natports[$key][$port['key']]['publicport'], $connecttext); 
+					$connecttext = preg_replace("/{$port['key']}/", $natports[$key][$port['key']]['publicport'], $connecttext);
 					$connectMethods[$key]['connectports'][] = "{$port['protocol']}:{$port['port']}:{$natports[$key][$port['key']]['publicport']}";
 				}
 				else {
 					if((preg_match('/remote desktop/i', $cm['description']) ||
-					   preg_match('/RDP/i', $cm['description'])) && 
+					   preg_match('/RDP/i', $cm['description'])) &&
 					   $port['key'] == '#Port-TCP-3389#') {
-						$connecttext = preg_replace("/{$port['key']}/", $user['rdpport'], $connecttext); 
+						$connecttext = preg_replace("/{$port['key']}/", $user['rdpport'], $connecttext);
 						$connectMethods[$key]['connectports'][] = "{$port['protocol']}:{$port['port']}:{$user['rdpport']}";
 					}
 					else {
-						$connecttext = preg_replace("/{$port['key']}/", $port['port'], $connecttext); 
+						$connecttext = preg_replace("/{$port['key']}/", $port['port'], $connecttext);
 						$connectMethods[$key]['connectports'][] = "{$port['protocol']}:{$port['port']}:{$port['port']}";
 					}
 				}
@@ -880,7 +880,7 @@
 		$cmid = $tmp[0];
 		if(empty($natports))
 			if((preg_match('/remote desktop/i', $connectMethods[$cmid]['description']) ||
-			   preg_match('/RDP/i', $connectMethods[$cmid]['description'])) && 
+			   preg_match('/RDP/i', $connectMethods[$cmid]['description'])) &&
 				$portdata[$cmid][0]['port'] == 3389)
 				$connectport = $user['rdpport'];
 			else
@@ -1005,7 +1005,7 @@
 	if($timeToNext > -1) {
 		$lockedall = 1;
 		if(count($request['reservations']) > 1) {
-			# get semaphore on each existing node in cluster so that nothing 
+			# get semaphore on each existing node in cluster so that nothing
 			# can get moved to the nodes during this process
 			$checkend = unixToDatetime($endts + 900);
 			foreach($request["reservations"] as $res) {
@@ -1721,7 +1721,7 @@
 			$node['id'] = $id;
 			array_push($nodes, $node);
 			array_push($stack, $node);
-		} 
+		}
 		while(count($stack)) {
 			$item = array_shift($stack);
 			$children = getChildNodes($item['id']);
@@ -1962,7 +1962,7 @@
 
 	$privileges = array();
 	$nodePrivileges = getNodePrivileges($nodeid, 'usergroups');
-	$cascadedNodePrivileges = getNodeCascadePrivileges($nodeid, 'usergroups'); 
+	$cascadedNodePrivileges = getNodeCascadePrivileges($nodeid, 'usergroups');
 	$cngp = $cascadedNodePrivileges['usergroups'];
 	$ngp = $nodePrivileges['usergroups'];
 	if(array_key_exists($groupid, $cngp)) {
@@ -2180,7 +2180,7 @@
 			             'errormsg' => 'resource group does not exist');
 		}
 		$np = getNodePrivileges($nodeid, 'resources');
-		$cnp = getNodeCascadePrivileges($nodeid, 'resources'); 
+		$cnp = getNodeCascadePrivileges($nodeid, 'resources');
 		$key = "$type/$name/$groupid";
 		if(isset($np['resources'][$key]['block']) || ! isset($cnp['resources'][$key]))
 			$privs = array_keys($np['resources'][$key]);
@@ -2399,9 +2399,9 @@
 	// Filter out any groups to which the user does not have access.
 	$usergroups = array();
 	foreach($groups as $id => $group) {
-		if($group['ownerid'] == $user['id'] || 
+		if($group['ownerid'] == $user['id'] ||
 		   (array_key_exists("editgroupid", $group) &&
-		   array_key_exists($group['editgroupid'], $user["groups"])) || 
+		   array_key_exists($group['editgroupid'], $user["groups"])) ||
 		   (array_key_exists($id, $user["groups"]))) {
 			array_push($usergroups, $group);
 		}
@@ -2476,7 +2476,7 @@
 		             'errormsg' => 'user group with submitted name and affiliation does not exist');
 	}
 	// if not owner and not member of managing group, no access
-	if($user['id'] != $row['ownerid'] && 
+	if($user['id'] != $row['ownerid'] &&
 	   ! array_key_exists($row['editgroupid'], $user['groups'])) {
 		return array('status' => 'error',
 		             'errorcode' => 69,
@@ -2854,7 +2854,7 @@
 		             'errorcode' => 18,
 		             'errormsg' => 'user group with submitted name and affiliation does not exist');
 	}
-	// if custom and not owner and not member of managing group or 
+	// if custom and not owner and not member of managing group or
 	//    custom/courseroll and no federated user group access, no access to delete group
 	if(($row['custom'] == 1 && $user['id'] != $row['ownerid'] &&
 	   ! array_key_exists($row['editgroupid'], $user['groups'])) ||
@@ -2930,7 +2930,7 @@
 		             'errormsg' => 'user group with submitted name and affiliation does not exist');
 	}
 	// if not owner and not member of managing group, no access
-	if($user['id'] != $row['ownerid'] && 
+	if($user['id'] != $row['ownerid'] &&
 	   ! array_key_exists($row['editgroupid'], $user['groups'])) {
 		return array('status' => 'error',
 		             'errorcode' => 28,
@@ -3012,7 +3012,7 @@
 		             'errormsg' => 'user group with submitted name and affiliation does not exist');
 	}
 	// if not owner and not member of managing group, no access
-	if($user['id'] != $row['ownerid'] && 
+	if($user['id'] != $row['ownerid'] &&
 	   ! array_key_exists($row['editgroupid'], $user['groups'])) {
 		return array('status' => 'error',
 		             'errorcode' => 28,
@@ -3655,7 +3655,7 @@
 	$stagCnt = 0;
 	$stagTime = 60;        # stagger reload reservations by 1 min
 	if($imgLoadTime > 840) // if estimated load time is > 14 min
-		$stagTime = 120;    #    stagger reload reservations by 2 min 
+		$stagTime = 120;    #    stagger reload reservations by 2 min
 	for($i = 0; $i < $reqToAlloc; $i++) {
 		$stagunixstart = $unixstart - $loadtime - ($stagCnt * $stagTime);
 		$stagstart = unixToDatetime($stagunixstart);
@@ -4003,8 +4003,8 @@
 	        . "LEFT JOIN OS os ON (i.OSid = os.id) "
 	        . "LEFT JOIN ("
 	        .      "SELECT rs.imageid, "
-	        .             "MAX(rq.id) AS requestid, " 
-	        .             "COUNT(rq.id) AS reqcount " 
+	        .             "MAX(rq.id) AS requestid, "
+	        .             "COUNT(rq.id) AS reqcount "
 	        .      "FROM reservation rs, "
 	        .           "request rq "
 	        .      "WHERE rs.requestid = rq.id AND "
@@ -4200,7 +4200,7 @@
 		             'errormsg' => "Specified duration is too long",
 		             'maxduration' => $allowed);
 	}
-	
+
 	$query = "SELECT id "
 	       . "FROM oneclick "
 	       . "WHERE id = $oneclickid AND "
@@ -4218,7 +4218,7 @@
 		             'errorcode' => 90,
 		             'errormsg' => "The OneClick with ID $oneclickid does not belong to the user that requested it.");
 	}*/
-	
+
 	$query = "UPDATE oneclick "
 	       . "SET imageid = $imageid, "
 	       .     "name = '$name', "
@@ -4255,7 +4255,7 @@
 function XMLRPCdeleteOneClick($oneclickid) {
 	global $user;
 	$oneclickid = processInputData($oneclickid, ARG_NUMERIC);
-	
+
 	$query = "SELECT id "
 	       . "FROM oneclick "
 	       . "WHERE id = $oneclickid AND "
diff --git a/web/index.php b/web/index.php
index 0f6a6cd..e8a48b8 100644
--- a/web/index.php
+++ b/web/index.php
@@ -21,16 +21,14 @@
 
 require_once(".ht-inc/conf.php");
 
-if (SSLOFFLOAD == 0) {
-    if(! isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
-        header("Location: " . BASEURL . "/");
-        exit;
-    }
+if(SSLOFFLOAD == 0) {
+	if(! isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") {
+		header("Location: " . BASEURL . "/");
+		exit;
+	}
 }
 
-$user = '';
-$mysqli_link_vcl = '';
-$mysqli_link_acct = '';
+$user = array();
 $mode = '';
 $oldmode = '';
 $submitErr = '';
diff --git a/web/js/code.js b/web/js/code.js
index 0b2c024..3391500 100644
--- a/web/js/code.js
+++ b/web/js/code.js
@@ -226,7 +226,7 @@
 	if(document.styleSheets[0].cssRules)  // Standards Compliant
 		cssobj = document.styleSheets[0].cssRules;
 	else
-		cssobj = document.styleSheets[0].rules;  // IE 
+		cssobj = document.styleSheets[0].rules;  // IE
 	var stop = 0;
 	for(var i = 0; i < cssobj.length; i++) {
 		if(cssobj[i].selectorText) {
diff --git a/web/js/dashboard.js b/web/js/dashboard.js
index 59922f2..0591c5c 100644
--- a/web/js/dashboard.js
+++ b/web/js/dashboard.js
@@ -203,6 +203,7 @@
 	    +  '<th>ReqID</th>'
 	    +  '<th>User</th>'
 	    +  '<th>Computer</th>'
+	    +  '<th>VM Host</th>'
 	    +  '<th>States</th>'
 	    +  '<th>Image</th>'
 	    +  '<th>Install Type</th>'
@@ -222,6 +223,8 @@
 		    + '</td><td style=\"padding: 1px; border-right: 1px solid;\">'
 		    + data[i].computer
 		    + '</td><td style=\"padding: 1px; border-right: 1px solid;\">'
+		    + data[i].vmhost
+		    + '</td><td style=\"padding: 1px; border-right: 1px solid;\">'
 		    + data[i].state
 		    + '</td><td style=\"padding: 1px; border-right: 1px solid;\">'
 		    + data[i].image
diff --git a/web/js/requests.js b/web/js/requests.js
index 4a28222..b8272f9 100644
--- a/web/js/requests.js
+++ b/web/js/requests.js
@@ -875,7 +875,7 @@
 	oldstore = dijit.byId('configvariables').store;
 	dijit.byId('configvariables').setStore(newstore2, '', {query: {id: ''}});
 	delete oldstore;
-	
+
 	// finishconfigs
 	/*if(data.items.configs.length == 0)
 		dijit.byId('newResDlgShowConfigBtn').set('disabled', true);
@@ -1388,7 +1388,7 @@
 		dijit.byId('serverdeletedlg').show();
 		return;
 	}
-	if(dijit.byId('serverdeletedlg') && 
+	if(dijit.byId('serverdeletedlg') &&
 	   dijit.byId('serverdeletedlg').open) {
 		dijit.byId('serverdeletedlg').hide();
 		dijit.byId('serverDeleteDlgBtn').set('disabled', false);
@@ -1552,7 +1552,7 @@
 		data.day = dijit.byId('day').value;
 	if(dijit.byId('editstarttime')) {
 		var t = dijit.byId('editstarttime').value;
-		data.starttime = dojox.string.sprintf('%02d%02d', 
+		data.starttime = dojox.string.sprintf('%02d%02d',
 		                                      t.getHours(),
 		                                      t.getMinutes());
 		var tmp = dijit.byId('day').value.match(/([0-9]{4})([0-9]{2})([0-9]{2})/);
@@ -1583,7 +1583,7 @@
 		data.endmode = 'length';
 	}
 	else if((dojo.byId('dateradio') && dojo.byId('dateradio').checked) ||
-	        (dijit.byId('openenddate') && ! dojo.byId('indefiniteradio')) || 
+	        (dijit.byId('openenddate') && ! dojo.byId('indefiniteradio')) ||
 	        (dijit.byId('openenddate') && dojo.byId('indefiniteradio') && ! dojo.byId('indefiniteradio').checked)) {
 		var d = dijit.byId('openenddate').value;
 		var t = dijit.byId('openendtime').value;
diff --git a/web/js/resources/computer.js b/web/js/resources/computer.js
index 6e511ea..dd08e37 100644
--- a/web/js/resources/computer.js
+++ b/web/js/resources/computer.js
@@ -210,6 +210,32 @@
 	return 0;
 }
 
+Computer.prototype.ipsort = function(a, b) {
+	var aparts = a.split('.');
+	var bparts = b.split('.');
+	for(var i = 0; i < 4; i++) {
+		aparts[i] = parseInt(aparts[i]);
+		bparts[i] = parseInt(bparts[i]);
+	}
+	if(aparts[0] < bparts[0])
+		return -1;
+	if(aparts[0] > bparts[0])
+		return 1;
+	if(aparts[1] < bparts[1])
+		return -1;
+	if(aparts[1] > bparts[1])
+		return 1;
+	if(aparts[2] < bparts[2])
+		return -1;
+	if(aparts[2] > bparts[2])
+		return 1;
+	if(aparts[3] < bparts[3])
+		return -1;
+	if(aparts[3] > bparts[3])
+		return 1;
+	return 0;
+}
+
 Computer.prototype.comparehostnames = function(a, b) {
 	// get hostname
 	var tmp = a.split('.');
@@ -291,6 +317,8 @@
 		resourcestore.comparatorMap['procnumber'] = resource.nocasesort;
 		resourcestore.comparatorMap['procspeed'] = resource.nocasesort;
 		resourcestore.comparatorMap['network'] = resource.nocasesort;
+		resourcestore.comparatorMap['IPaddress'] = resource.ipsort;
+		resourcestore.comparatorMap['privateIPaddress'] = resource.ipsort;
 
 		dojo.connect(resourcegrid, '_onFetchComplete', function() {dojo.byId('computercount').innerHTML = 'Computers in table: ' + resourcegrid.rowCount;});
 	}
@@ -1216,7 +1244,9 @@
 	                               procnumber: resource.nocasesort,
 	                               procspeed: resource.nocasesort,
 	                               network: resource.nocasesort,
-	                               ram: resource.nocasesort};
+	                               ram: resource.nocasesort,
+	                               IPaddress: resource.ipsort,
+	                               privateIPaddress: resource.ipsort};
 	resourcestore.fetch();
 	savescroll = resourcegrid.scrollTop;
 	resourcegrid.setStore(resourcestore, resourcegrid.query);
diff --git a/web/js/resources/image.js b/web/js/resources/image.js
index b710c55..4ad565d 100644
--- a/web/js/resources/image.js
+++ b/web/js/resources/image.js
@@ -137,6 +137,12 @@
 	}
 }
 
+function initAddDialog() {
+	if(dijit.byId('addomainid').options.length == 0) {
+		dijit.byId('adauthenable').set('disabled', true);
+	}
+}
+
 function delayedEditResize() {
 	setTimeout(function() {resizeRecenterDijitDialog('addeditdlg');}, 300);
 }
@@ -781,6 +787,7 @@
 function submitCreateUpdateImage() {
 	if(dojo.byId('newimage').checked) {
 		dijit.byId('addeditdlg').show();
+		initAddDialog();
 		dijit.byId('startimagedlg').hide();
 		return;
 	}
diff --git a/web/js/vm.js b/web/js/vm.js
index 0864f9a..b56313b 100644
--- a/web/js/vm.js
+++ b/web/js/vm.js
@@ -183,6 +183,8 @@
 	if(data.items.failed) {
 		if(data.items.failed == 'nohostaccess')
 			alert('You do not have access to manage this VM host.');
+		if(data.items.failed == 'invaliddata')
+			alert('Invalid list of VMs submitted.');
 		document.body.style.cursor = 'default';
 		return;
 	}
@@ -300,15 +302,18 @@
 		handleAs: "json",
 		error: errorHandler,
 		content: {continuation: cont,
-					 listids: listids.join(','),
-					 hostid: hostid},
+		          listids: listids.join(','),
+		          hostid: hostid},
 		timeout: 15000
 	});
 }
 
 function vmFromHostCB(data, ioArgs) {
 	if(data.items.failed) {
-		alert('You do not have access to manage this VM host.');
+		if(data.items.failed == 'nohostaccess')
+			alert('You do not have access to manage this VM host.');
+		if(data.items.failed == 'invaliddata')
+			alert('Invalid list of VMs submitted.');
 		document.body.style.cursor = 'default';
 		return;
 	}
@@ -412,7 +417,10 @@
 
 function reloadVMhostCB(data, ioArgs) {
 	if(data.items.failed) {
-		alert('You do not have access to manage this VM host.');
+		if(data.items.failed == 'nohostaccess')
+			alert('You do not have access to manage this VM host.');
+		if(data.items.failed == 'invaliddata')
+			alert('Invalid list of VMs submitted.');
 		document.body.style.cursor = 'default';
 		return;
 	}
diff --git a/web/locale/po_files/es_CR/vcl.po b/web/locale/po_files/es_CR/vcl.po
index b117b2f..8e7af8c 100644
--- a/web/locale/po_files/es_CR/vcl.po
+++ b/web/locale/po_files/es_CR/vcl.po
@@ -3956,7 +3956,7 @@
 "message has a default. Additionally, separate messages can be configured for "
 "each affiliation. Most of the messages will have parts that are in square "
 "brackets. These parts will have data substituted for them before the message "
-"is sent. A list of what can be used in squeare brackets can be found at the "
+"is sent. A list of what can be used in square brackets can be found at the "
 "<a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form "
 "that may be sent such as in the form of a popup within a reservation when "
 "the reservation is about to end."
diff --git a/web/locale/po_files/es_MX/vcl.po b/web/locale/po_files/es_MX/vcl.po
index 9ce5ea1..7664d61 100644
--- a/web/locale/po_files/es_MX/vcl.po
+++ b/web/locale/po_files/es_MX/vcl.po
@@ -3109,7 +3109,7 @@
 
 #: siteconfig.php:1517
 #, php-format
-msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in squeare brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
+msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in square brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
 msgstr ""
 
 #: siteconfig.php:1582
diff --git a/web/locale/po_files/fr_CA/vcl.po b/web/locale/po_files/fr_CA/vcl.po
index dba6843..c0d7e13 100644
--- a/web/locale/po_files/fr_CA/vcl.po
+++ b/web/locale/po_files/fr_CA/vcl.po
@@ -3108,7 +3108,7 @@
 
 #: siteconfig.php:1517
 #, php-format
-msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in squeare brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
+msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in square brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
 msgstr ""
 
 #: siteconfig.php:1582
diff --git a/web/locale/po_files/pt_PT/vcl.po b/web/locale/po_files/pt_PT/vcl.po
index cf649dd..e904bdb 100644
--- a/web/locale/po_files/pt_PT/vcl.po
+++ b/web/locale/po_files/pt_PT/vcl.po
@@ -3109,7 +3109,7 @@
 
 #: siteconfig.php:1517
 #, php-format
-msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in squeare brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
+msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in square brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
 msgstr ""
 
 #: siteconfig.php:1582
diff --git a/web/locale/po_files/vcl.po.template b/web/locale/po_files/vcl.po.template
index bd58afc..470becf 100644
--- a/web/locale/po_files/vcl.po.template
+++ b/web/locale/po_files/vcl.po.template
@@ -3109,7 +3109,7 @@
 
 #: siteconfig.php:1517
 #, php-format
-msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in squeare brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
+msgid "This section allows for configuration of messages that are sent to users and administrators about things such as reservations and image management. Every message has a default. Additionally, separate messages can be configured for each affiliation. Most of the messages will have parts that are in square brackets. These parts will have data substituted for them before the message is sent. A list of what can be used in square brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. Some messages also have a short form that may be sent such as in the form of a popup within a reservation when the reservation is about to end."
 msgstr ""
 
 #: siteconfig.php:1582