You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by jf...@apache.org on 2014/09/11 18:01:49 UTC

svn commit: r1624325 [2/13] - in /vcl/trunk/web: ./ .ht-inc/ .ht-inc/authmethods/ css/ js/ js/resources/

Added: vcl/trunk/web/.ht-inc/computer.php
URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/computer.php?rev=1624325&view=auto
==============================================================================
--- vcl/trunk/web/.ht-inc/computer.php (added)
+++ vcl/trunk/web/.ht-inc/computer.php Thu Sep 11 16:01:48 2014
@@ -0,0 +1,4354 @@
+<?php
+/*
+  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.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  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.
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class Computer
+///
+/// \brief extends Resource class to add things specific to resources of the
+/// computer type
+///
+////////////////////////////////////////////////////////////////////////////////
+class Computer extends Resource {
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn __construct()
+	///
+	/// \brief calls parent constructor; initializes things for Computer class
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function __construct() {
+		parent::__construct();
+		$this->restype = 'computer';
+		$this->restypename = 'Computer';
+		$this->namefield = 'hostname';
+		$this->defaultGetDataArgs = array('sort' => 0,
+		                                  'includedeleted' => 0,
+		                                  'rscid' => '');
+		$this->basecdata['obj'] = $this;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn getData($args)
+	///
+	/// \param $args - array of arguments that determine what data gets returned;
+	/// must include:\n
+	/// \param $sort - (optional) 1 to sort computers; 0 not to
+	/// \b includedeleted - 0 or 1; include deleted images\n
+	/// \b rscid - only return data for resource with this id; pass 0 for all
+	/// (from image table)
+	///
+	/// \return array of data as returned from getImages
+	///
+	/// \brief wrapper for calling getImages
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function getData($args) {
+		return getComputers($args['sort'], $args['includedeleted'], $args['rscid']);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn fieldDisplayName($field)
+	///
+	/// \param $field - name of a resource field
+	///
+	/// \return display value for $field
+	///
+	/// \brief generates the display value for $field
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function fieldDisplayName($field) {
+		switch($field) {
+			case 'currentimg':
+				return 'Current Image';
+			case 'nextimg':
+				return 'Next Image';
+			case 'ram':
+				return 'RAM';
+			case 'procnumber':
+				return 'Cores';
+			case 'procspeed':
+				return 'Processor speed';
+			case 'network':
+				return 'Network speed';
+			case 'IPaddress':
+				return 'Public IP Address';
+			case 'privateIPaddress':
+				return 'Private IP Address';
+			case 'eth0macaddress':
+				return 'Private MAC Address';
+			case 'eth1macaddress':
+				return 'Public MAC Address';
+			case 'vmhost':
+				return 'VM Host';
+			case 'provisioning':
+				return 'Provisioning Engine';
+		}
+		return ucfirst($field);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn extraResourceFilters()
+	///
+	/// \return html
+	///
+	/// \brief generates HTML for computer utilities drop down and filtering by
+	/// computer group
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function extraResourceFilters() {
+		$h = '';
+
+		# selected items menu
+		$h .= "<div dojoType=\"dijit.form.DropDownButton\">\n";
+		$h .= "<span>" . _("Actions for selected computers") . "</span>\n";
+		$h .= "<div dojoType=\"dijit.Menu\" id=\"actionmenu\">\n";
+
+		# reload
+		$resources = getUserResources(array("imageAdmin", "imageCheckOut"));
+		if(count($resources['image'])) {
+			$h .= "  <div dojoType=\"dijit.PopupMenuItem\">\n";
+			$h .= "    <span>Reload with an Image</span>\n";
+			$h .= "    <div dojoType=\"dijit.layout.ContentPane\"\n";
+			$h .= "         style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n";
+			$h .= "      Reload computers with the following image:<br>\n";
+			$h .= selectInputAutoDijitHTML('', $resources['image'], 'reloadimageid');
+			$cont = addContinuationsEntry('AJreloadComputers', $this->basecdata);
+			$h .= "      <input type=\"hidden\" id=\"reloadcont\" value=\"$cont\"><br>\n";
+			$h .= dijitButton('', 'Confirm Reload Computers', 'confirmReload();', 0);
+			$h .= "    </div>\n";
+			$h .= "  </div>\n";
+		}
+
+		# delete
+		$h .= "  <div dojoType=\"dijit.MenuItem\"\n";
+		$h .= "       onClick=\"confirmDelete\">\n";
+		$h .= "    Delete Computers\n";
+		$cont = addContinuationsEntry('AJdeleteComputers', $this->basecdata);
+		$h .= "      <input type=\"hidden\" id=\"deletecont\" value=\"$cont\"><br>\n";
+		$h .= "  </div>\n";
+
+		# change state
+		$states = array("2" => "available",
+		                "23" => "hpc",
+		                "10" => "maintenance",
+		                "20" => "convert to vmhostinuse");
+		$h .= "  <div dojoType=\"dijit.PopupMenuItem\">\n";
+		$h .= "    <span>Change State</span>\n";
+		$h .= "    <div dojoType=\"dijit.layout.ContentPane\"\n";
+		$h .= "         style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n";
+		$h .= "      Change state to:<br>\n";
+		$h .= selectInputAutoDijitHTML('', $states, 'newstateid');
+		$cdata = $this->basecdata;
+		$cdata['states'] = $states;
+		$cont = addContinuationsEntry('AJcompStateChange', $cdata);
+		$h .= "      <input type=\"hidden\" id=\"statechangecont\" value=\"$cont\"><br>\n";
+		$h .= dijitButton('', 'Confirm State Change', 'confirmStateChange();', 0);
+		$h .= "    </div>\n";
+		$h .= "  </div>\n";
+
+		# change schedule
+		$resources = getUserResources(array("scheduleAdmin"), array("manageGroup"));
+		if(count($resources['schedule'])) {
+			$h .= "  <div dojoType=\"dijit.PopupMenuItem\">\n";
+			$h .= "    <span>Change Schedule</span>\n";
+			$h .= "    <div dojoType=\"dijit.layout.ContentPane\"\n";
+			$h .= "         style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n";
+			$h .= "      Change schedule to:<br>\n";
+			$h .= selectInputAutoDijitHTML('', $resources['schedule'], 'newscheduleid');
+			$cont = addContinuationsEntry('AJcompScheduleChange', $this->basecdata);
+			$h .= "      <input type=\"hidden\" id=\"schedulecont\" value=\"$cont\"><br>\n";
+			$h .= dijitButton('', 'Confirm Schedule Change', 'confirmScheduleChange();', 0);
+			$h .= "    </div>\n";
+			$h .= "  </div>\n";
+		}
+
+		# change provisioning engine
+		$provisioning = getProvisioning();
+		$h .= "  <div dojoType=\"dijit.PopupMenuItem\">\n";
+		$h .= "    <span>Change Provisioning Engine</span>\n";
+		$h .= "    <div dojoType=\"dijit.layout.ContentPane\"\n";
+		$h .= "         style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n";
+		$h .= "      Change Provisioning Engine to:<br>\n";
+		$h .= selectInputAutoDijitHTML('', $provisioning, 'newprovisioningid');
+		$cdata = $this->basecdata;
+		$cont = addContinuationsEntry('AJcompProvisioningChange', $cdata);
+		$h .= "      <input type=\"hidden\" id=\"provisioningchangecont\" value=\"$cont\"><br>\n";
+		$h .= dijitButton('', 'Confirm Provisioning Engine Change', 'confirmProvisioningChange();', 0);
+		$h .= "    </div>\n";
+		$h .= "  </div>\n";
+
+		# generate private dhcpd data
+		$h .= "  <div dojoType=\"dijit.PopupMenuItem\">\n";
+		$h .= "    <span>Generate Private dhcpd Data</span>\n";
+		$h .= "    <div dojoType=\"dijit.layout.ContentPane\"\n";
+		$h .= "         style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n";
+		$h .= "      Enter the Management Node Private IP Address:<br>\n";
+		$h .= "      <input type=\"text\" dojoType=\"dijit.form.TextBox\" id=\"mnprivipaddr\" ";
+		$h .= "required=\"false\"><br><br>\n";
+		$h .= "      Select which NIC is used for the Private interface:<br>\n";
+		$h .= "      <input type=\"radio\" name=\"prnic\" value=\"eth0\" id=\"preth0rdo\" ";
+		$h .= "checked=\"checked\"><label for=\"eth0rdo\">eth0</label><br>\n";
+		$h .= "      <input type=\"radio\" name=\"prnic\" value=\"eth1\" id=\"preth1rdo\">";
+		$h .= "<label for=\"eth1rdo\">eth1</label><br>\n";
+		$h .= dijitButton('', 'Generate Data', "generateDHCPdata('private');", 0);
+		$cont = addContinuationsEntry('AJgenerateDHCPdata', $this->basecdata);
+		$h .= "      <input type=\"hidden\" id=\"privatedhcpcont\" value=\"$cont\">\n";
+		$h .= "    </div>\n";
+		$h .= "  </div>\n";
+
+		# generate public dhcpd data
+		$h .= "  <div dojoType=\"dijit.PopupMenuItem\">\n";
+		$h .= "    <span>Generate Public dhcpd Data</span>\n";
+		$h .= "    <div dojoType=\"dijit.layout.ContentPane\"\n";
+		$h .= "         style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n";
+		$h .= "      Select which NIC is used for the Public interface:<br>\n";
+		$h .= "      <input type=\"radio\" name=\"punic\" value=\"eth0\" id=\"pueth0rdo\">";
+		$h .= "<label for=\"eth0rdo\">eth0</label><br>\n";
+		$h .= "      <input type=\"radio\" name=\"punic\" value=\"eth1\" id=\"pueth1rdo\" ";
+		$h .= "checked=\"checked\"><label for=\"eth1rdo\">eth1</label><br>\n";
+		$h .= dijitButton('', 'Generate Data', "generateDHCPdata('public');", 0);
+		$h .= "      <input type=\"hidden\" id=\"publicdhcpcont\" value=\"$cont\">\n"; # use previous continuation
+		$h .= "    </div>\n";
+		$h .= "  </div>\n";
+
+		# generate /etc/hosts data
+		$h .= "  <div dojoType=\"dijit.MenuItem\"\n";
+		$h .= "       onClick=\"hostsData\">\n";
+		$h .= "    Generate /etc/hosts Data\n";
+		$cont = addContinuationsEntry('AJhostsData', $this->basecdata);
+		$h .= "      <input type=\"hidden\" id=\"hostsdatacont\" value=\"$cont\"><br>\n";
+		$h .= "  </div>\n";
+
+		$h .= "</div>\n"; # close Menu
+		$h .= "</div>\n"; # close DropDownButton
+
+		# computer groups
+		$tmp = getUserResources(array($this->restype . 'Admin'), array('manageGroup'), 1);
+		$groups = $tmp[$this->restype];
+		$cont = addContinuationsEntry('AJfilterCompGroups', $this->basecdata);
+		$h .= "<input type=\"hidden\" id=\"filtercompgroupscont\" value=\"$cont\">\n";
+		$h .= "<div dojoType=\"dijit.form.DropDownButton\">\n";
+		$h .= "  <span>Selected Computer Groups</span>\n";
+		$h .= "  <div dojoType=\"dijit.TooltipDialog\" id=\"connectmethodttd\">\n";
+		$size = 10;
+		if(count($groups) < 10)
+			$size = count($groups);
+		$h .= selectInputHTML('', $groups, 'filtercompgroups',
+		                      "onChange=\"delayedCompGroupFilterSelection();\" size=\"$size\"",
+		                      -1, 0, 1);
+		$h .= "  </div>\n"; # tooltip dialog
+		$h .= "</div>\n"; # drop down button
+
+		$h .= "<div dojoType=dijit.Dialog\n";
+		$h .= "      id=\"confirmactiondlg\"\n";
+		$h .= "      duration=250\n";
+		$h .= "      autofocus=false\n";
+		$h .= "      draggable=true>\n";
+		#$h .= "<div id=\"actionmsg\"></div>\n";
+		$h .= "<div dojoType=\"dijit.layout.ContentPane\" id=\"actionmsg\"\n";
+		$h .= "         style=\"background-color: white; padding: 5px;\">\n";
+		$h .= "</div>\n";
+		$h .= "<div id=\"complist\" style=\"height: 87%; overflow: auto;\"></div>\n";
+		$h .= "<input type=\"hidden\" id=\"submitcont\">\n";
+		$h .= "<div style=\"text-align: center;\">\n";
+		$h .= "<span id=\"submitactionbtnspan\">\n";
+		$h .= dijitButton('submitactionbtn', 'Submit', 'submitAction();', 0);
+		$h .= "</span>\n";
+		$h .= dijitButton('cancelactionbtn', 'Cancel', 'cancelAction();', 0);
+		$h .= "</div>\n"; # btn div
+		$h .= "</div>\n"; # confirmactiondlg
+
+		$h .= "<div dojoType=dijit.Dialog\n";
+		$h .= "      id=\"noschedulenoadd\"\n";
+		$h .= "      title=\"Cannot Add Computers\"\n";
+		$h .= "      duration=250\n";
+		$h .= "      autofocus=false\n";
+		$h .= "      draggable=true>\n";
+		$h .= "All computers must have a schedule assigned to them. You do not<br>\n";
+		$h .= "have to any schedules or no schedules exist. You must be granted<br>\n";
+		$h .= "access to or create at least one schedule to be able to add computers.<br><br>\n";
+		$h .= "<div style=\"text-align: center;\">\n";
+		$h .= dijitButton('', 'Close', 'dijit.byId("noschedulenoadd").hide();', 0);
+		$h .= "</div>\n"; # btn div
+		$h .= "</div>\n"; # noschedulenoadd
+
+		# filter table
+		$h .= "<div id=\"extrafiltersdiv\" style=\"height: 65px;\"></div>\n";
+		return $h;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn AJfilterCompGroups
+	///
+	/// \brief generates regular expressions to match ids of all computers in the
+	/// submitted computer groups
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function AJfilterCompGroups() {
+		$groupids = processInputVar('groupids', ARG_STRING);
+		if(! preg_match('/^[0-9,]+$/', $groupids)) {
+			$ret = array('status' => 'error',
+			             'errormsg' => "Invalid data submitted.");
+			sendJSON($ret);
+			return;
+		}
+		$groupids = explode(',', $groupids);
+		$tmp = getUserResources(array($this->restype . 'Admin'), array('manageGroup'), 1);
+		$groups = $tmp[$this->restype];
+		$groupnames = array();
+		foreach($groupids as $id) {
+			if(array_key_exists($id, $groups))
+				$groupnames[] = $groups[$id];
+		}
+		$comps = getResourcesFromGroups($groupnames, 'computer', 1);
+		$regids = "^" . implode('$|^', array_keys($comps)) . "$";
+		$arr = array('status' => 'success',
+		             'regids' => $regids);
+		sendJSON($arr);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn addEditDialogHTML($add)
+	///
+	/// \param $add - unused for this class
+	///
+	/// \brief generates HTML for dialog used to edit resource
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function addEditDialogHTML($add) {
+		global $user;
+		# dialog for on page editing
+		$h = '';
+		$h .= "<div dojoType=dijit.Dialog\n";
+		$h .= "      id=\"addeditdlg\"\n";
+		$h .= "      title=\"Edit {$this->restypename}\"\n";
+		$h .= "      duration=250\n";
+		$h .= "      draggable=true>\n";
+		$h .= "<div id=\"addeditdlgcontent\">\n";
+		$h .= "<div id=\"computerdlgcontent\">\n";
+		# id
+		$h .= "<input type=\"hidden\" id=\"editresid\">\n";
+
+		$types = array("blade" => "Bare Metal", "lab" => "Lab", "virtualmachine" => "Virtual Machine");
+		$provisioning = getProvisioning();
+		$provtypes = getProvisioningTypes();
+		$states = array('blade'          => array(2 => 'available',
+		                                          10 => 'maintenance',
+		                                          20 => 'vmhostinuse'),
+		                'lab'            => array(2 => 'available',
+		                                          10 => 'maintenance'),
+		                'virtualmachine' => array(10 => 'maintenance'));
+
+		$h .= "<script type=\"text/javascript\">\n";
+		$h .= "var options = {\n";
+		$options = array();
+		foreach($types as $type => $tmp) {
+			$opt = '';
+			$opt .= "  $type: {\n";
+			$opt .= "    provisioning: [\n";
+			$arr = array();
+			foreach($provtypes[$type] as $key => $val)
+				$arr[] = "      {value: '$key', label: '$val'}";
+			$opt .= implode(",\n", $arr);
+			$opt .= "\n    ],\n";
+			$opt .= "    states: [\n";
+			$arr = array();
+			foreach($states[$type] as $key => $val)
+				$arr[] = "      {value: '$key', label: '$val'}";
+			$opt .= implode(",\n", $arr);
+			$opt .= "\n    ]\n";
+			$opt .= "  }";
+			$options[] = $opt;
+		}
+		$h .= implode(",\n", $options);
+		$h .= "\n}\n";
+		$h .= "</script>\n";
+
+		# add single or multiple
+		$h .= "<div id=\"singlemultiplediv\" class=\"hidden\">\n";
+		/*$h .= "<label for=\"addsingle\">Add Single Computer</label><span ";
+		$h .= "class=\"labeledform\"><input type=\"radio\" name=\"mode\" ";
+		$h .= "id=\"addsingle\" checked=\"checked\" onclick=\"toggleAddSingle();\">";
+		$h .= "</span><br><br>\n";
+		$h .= "<label for=\"addmultiple\">Add Multiple Computers</label><span ";
+		$h .= "class=\"labeledform\"><input type=\"radio\" name=\"mode\" ";
+		$h .= "id=\"addmultiple\" onclick=\"toggleAddMultiple();\"><br><br>\n";*/
+		$extra = array('onChange' => 'toggleSingleMultiple();');
+		$modes = array('single' => 'Single Computer',
+		               'multiple' => 'Multiple Computers');
+		$h .= labeledFormItem('mode', 'Add ', 'select', $modes, 1, '', '', '', $extra);
+		$h .= "<br>\n";
+		$h .= "</div>\n"; # singlemultiplediv
+
+		# add multiple note
+		$h .= "<div id=\"multiplenotediv\" class=\"hidden\">\n";
+		$h .= "<b>NOTE</b>: 'Start IP' and 'End IP' can only differ in the number ";
+		$h .= "after the last '.'. The<br>hostnames will be generated from the ";
+		$h .= "'Hostname' field. The hostnames for each<br>computer can only differ ";
+		$h .= "by the value of a number in the first part of the hostname.<br>Place ";
+		$h .= "a '%' character in the 'Hostname' field where that number will be. ";
+		$h .= "Then fill in<br>'Start value' and 'End value' with the first and last ";
+		$h .= "values to be used in the hostname.<br><br>";
+		$h .= "</div>\n"; # multiplenotediv
+
+		# div for canceling moving blade to vmhostinuse
+		$h .= "<div class=\"highlightnoticewarn hidden\" id=\"cancelvmhostinusediv\">\n";
+		$h .= "<span id=\"tohostfuturespan\">\n";
+		$h .= "NOTICE: This computer is scheduled to start being reloaded as a vmhost at<br>";
+		$h .= "<span id=\"tohostfuturetimespan\"></span>";
+		$h .= ". You may cancel this scheduled<br>reload by clicking the button below.";
+		$h .= "<br><br></span>\n";
+		$h .= "<span id=\"tohostnowspan\">\n";
+		$h .= "NOTICE: This computer is currently being reloaded as a vmhost. You may cancel this<br>";
+		$h .= "process by clicking on the button below. After canceling the reload, it may take several<br>";
+		$h .= "minutes for the cancellation process to complete.";
+		$h .= "<br><br></span>\n";
+		$h .= "<input type=\"hidden\" id=\"tohostcancelcont\">\n";
+		$h .= "<button dojoType=\"dijit.form.Button\">\n";
+		$h .= "	Cancel Scheduled Reload\n";
+		$h .= "	<script type=\"dojo/method\" event=onClick>\n";
+		$h .= "		cancelScheduledtovmhostinuse();\n";
+		$h .= "	</script>\n";
+		$h .= "</button>\n";
+		$h .= "</div>\n"; # cancelvmhostinusediv
+		$h .= "<div class=\"highlightnoticenotify hidden\" id=\"cancelvmhostinuseokdiv\"></div>\n";
+
+		# hostname
+		$errmsg = "Name can only contain letters, numbers, dashes(-), periods(.), and underscores(_). It can be from 1 to 36 characters long.";
+		$h .= labeledFormItem('name', 'Name*', 'text', '^([a-zA-Z0-9_][-a-zA-Z0-9_\.]{1,35})$',
+		                      1, '', $errmsg); 
+
+		# start/end
+		$h .= "<div id=\"startenddiv\" class=\"hidden\">\n";
+		$extra = array('smallDelta' => 1, 'largeDelta' => 10);
+		$h .= labeledFormItem('startnum', 'Start*', 'spinner', '{min:0,max:255,places:0}', 1);
+		$h .= labeledFormItem('endnum', 'End*', 'spinner', '{min:0,max:255,places:0}', 1);
+		$h .= "</div>\n"; # startenddiv
+
+		# owner
+		$extra = array('onKeyPress' => 'setOwnerChecking');
+		$h .= labeledFormItem('owner', 'Owner*', 'text', '', 1,
+		                      "{$user['unityid']}@{$user['affiliation']}", 'Unknown user',
+		                      'checkOwner', $extra);
+		$cont = addContinuationsEntry('AJvalidateUserid');
+		$h .= "<input type=\"hidden\" id=\"valuseridcont\" value=\"$cont\">\n";
+
+		# type
+		$extra = array('onChange' => 'selectType();');
+		$h .= labeledFormItem('type', 'Type', 'select', $types, 1, '', '', '', $extra);
+
+		# single computer fields
+		$h .= "<div id=\"singleipmacdiv\">\n";
+		# public IP
+		$ipreg = '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)';
+		$ipreg1 = "^$ipreg$";
+		$errmsg = "Invalid Public IP address specified - must be a valid IPV4 address";
+		$h .= labeledFormItem('ipaddress', 'Public IP Address*', 'text', $ipreg1, 1, '', $errmsg); 
+
+		# private IP
+		$errmsg = "Invalid Private IP address specified - must be a valid IPV4 address";
+		$h .= labeledFormItem('privateipaddress', 'Private IP Address', 'text', $ipreg1, 0, '', $errmsg); 
+
+		# Public MAC
+		$macreg = '^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$';
+		$errmsg = "Invalid Public MAC address specified";
+		$h .= labeledFormItem('publicmac', 'Public MAC Address', 'text', $macreg, 0, '', $errmsg); 
+
+		# private MAC
+		$errmsg = "Invalid Private MAC address specified";
+		$h .= labeledFormItem('privatemac', 'Private MAC Address', 'text', $macreg, 0, '', $errmsg); 
+
+		$h .= "</div>\n"; # singleipmacdiv
+
+		# multi computer fields
+		$h .= "<div id=\"multiipmacdiv\" class=\"hidden\">\n";
+		# start public IP
+		$errmsg = "Invalid Start Public IP Address specified - must be a valid IPV4 address";
+		$h .= labeledFormItem('startpubipaddress', 'Start Public IP Address*', 'text', $ipreg1, 1, '', $errmsg); 
+
+		# end public IP
+		$errmsg = "Invalid End Public IP Address specified - must be a valid IPV4 address";
+		$h .= labeledFormItem('endpubipaddress', 'End Public IP Address*', 'text', $ipreg1, 1, '', $errmsg); 
+
+		# start private IP
+		$errmsg = "Invalid Start Private IP Address specified - must be a valid IPV4 address";
+		$h .= labeledFormItem('startprivipaddress', 'Start Private IP Address*', 'text', $ipreg1, 1, '', $errmsg); 
+
+		# end private IP
+		$errmsg = "Invalid End Private IP Address specified - must be a valid IPV4 address";
+		$h .= labeledFormItem('endprivipaddress', 'End Private IP Address*', 'text', $ipreg1, 1, '', $errmsg); 
+
+		# start MAC
+		$errmsg = "Invalid Start MAC Address specified";
+		$h .= labeledFormItem('startmac', 'Start MAC Address', 'text', $macreg, 0, '', $errmsg); 
+
+		$h .= "</div>\n"; # multiipsdiv
+
+		# provisioning engine
+		$extra = array('onChange' => 'selectProvisioning();');
+		$h .= labeledFormItem('provisioningid', 'Provisioning Engine', 'selectonly', $provisioning, 1, '', '', '', $extra);
+
+		# state
+		$extra = array('onChange' => 'selectState();');
+		$states = array(2 => 'available',
+		                23 => 'hpc',
+		                10 => 'maintenance',
+		                20 => 'vmhostinuse');
+		$h .= labeledFormItem('stateid', 'State', 'selectonly', $states, 1, '', '', '', $extra);
+
+		# maintenance notes
+		$h .= "<div id=\"notesspan\">\n";
+		$h .= labeledFormItem('notes', 'Reason for maintenance', 'textarea');
+		$h .= "</div>\n";
+
+		# VMhost profile
+		$profiles = getVMProfiles();
+		uasort($profiles, 'sortKeepIndex');
+		$h .= "<div id=\"vmprofilespan\">\n";
+		$h .= labeledFormItem('vmprofileid', 'VM Host Porfile', 'select', $profiles);
+		$h .= "</div>\n";
+
+		# platform
+		$platforms = getPlatforms();
+		$h .= labeledFormItem('platformid', 'Platform', 'select', $platforms);
+
+		# schedule
+		$tmp = getUserResources(array("scheduleAdmin"), array("manageGroup"));
+		$schedules = $tmp["schedule"];
+		$h .= labeledFormItem('scheduleid', 'Schedule', 'select', $schedules);
+
+		# current image
+		$h .= "<div id=\"curimgspan\">\n";
+		$h .= "<label for=\"curimg\">Current Image:</label>\n";
+		$h .= "<span class=\"labeledform\" id=\"curimg\"></span><br>\n";
+		$h .= "</div>\n";
+
+		# ram
+		$extra = array('smallDelta' => 1024, 'largeDelta' => 4096);
+		$h .= labeledFormItem('ram', 'RAM (MB)*', 'spinner', '{min:500,max:16777215,places:0}', 1);
+
+		# cores
+		$extra = array('smallDelta' => 1, 'largeDelta' => 4);
+		$h .= labeledFormItem('cores', 'No. Cores*', 'spinner', '{min:1,max:255,places:0}', 1);
+
+		# proc speed
+		$extra = array('smallDelta' => 100, 'largeDelta' => 1000);
+		$h .= labeledFormItem('procspeed', 'Processor Speed (MHz)*', 'spinner', '{min:500,max:10000,places:0}', 1);
+
+		# network speed
+		$tmpArr = array("10" => "10", "100" => "100", "1000" => "1000", "10000" => "10000", "100000" => "100000");
+		$h .= labeledFormItem('network', 'Network', 'select', $tmpArr);
+
+		# compid
+		$h .= "<div id=\"compidspan\">\n";
+		$h .= "<label for=\"compid\">Computer ID:</label>\n";
+		$h .= "<span class=\"labeledform\" id=\"compid\"></span><br>\n";
+		$h .= "</div>\n";
+
+		# location
+		$errmsg = "Location can be up to 255 characters long and may contain letters, numbers, spaces, and these characters: - , . _ @ # ( )";
+		$h .= labeledFormItem('location', 'Location', 'text',
+		                      '^([-a-zA-Z0-9_\. ,@#\(\)]{0,255})$', 0, '', $errmsg); 
+
+		$h .= "</div>\n"; # computerdlgcontent
+		$h .= "</div>\n"; # addeditdlgcontent
+
+		$h .= "<div id=\"addeditdlgerrmsg\" class=\"nperrormsg\"></div>\n";
+
+		$h .= "<div id=\"editdlgbtns\" align=\"center\">\n";
+		$h .= dijitButton('addeditbtn', "Confirm", "saveResource();");
+		$h .= dijitButton('', "Cancel", "dijit.byId('addeditdlg').hide();");
+		$h .= "</div>\n"; # editdlgbtns
+		$h .= "</div>\n"; # dialog
+
+		$h .= "<div dojoType=dijit.Dialog\n";
+		$h .= "      id=\"groupingnote\"\n";
+		$h .= "      title=\"Computer Grouping\"\n";
+		$h .= "      duration=250\n";
+		$h .= "      draggable=true>\n";
+		$h .= "Computer(s) successfully added. Each computer needs<br>to be a member of a computer resource group. The<br>following dialog<br>will allow you to add the new<br>computer(s) to a group.<br><br>\n";
+		$h .= "<div align=\"center\">\n";
+		$h .= dijitButton('', "Close", "dijit.byId('groupingnote').hide();");
+		$h .= "</div>\n"; # btn div
+		$h .= "</div>\n"; # groupingnote
+
+		$h .= "<div dojoType=dijit.Dialog\n";
+		$h .= "      id=\"groupdlg\"\n";
+		$h .= "      title=\"Computer Grouping\"\n";
+		$h .= "      duration=250\n";
+		$h .= "      draggable=true>\n";
+		$h .= "<div id=\"groupdlgcontent\"></div>\n";
+		$h .= "<div align=\"center\">\n";
+		$script  = "    dijit.byId('groupdlg').hide();\n";
+		$script .= "    checkFirstAdd();\n";
+		$h .= dijitButton('', "Close", $script);
+		$h .= "</div>\n"; # btn div
+		$h .= "</div>\n"; # groupdlg
+		return $h;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn AJeditResource()
+	///
+	/// \brief sends data for editing a resource
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function AJeditResource() {
+		$rscid = processInputVar('rscid', ARG_NUMERIC);
+		$resources = getUserResources(array($this->restype . 'Admin'), array('administer'), 0, 1);
+		if(! array_key_exists($rscid, $resources[$this->restype])) {
+			$ret = array('status' => 'noaccess');
+			sendJSON($ret);
+			return;
+		}
+		$this->jsondata['showcancel'] = 0;
+		$query = "SELECT UNIX_TIMESTAMP(rq.start) AS start "
+		       . "FROM request rq, "
+		       .      "reservation rs, "
+		       .      "state ls, "
+		       .      "state cs "
+		       . "WHERE rs.requestid = rq.id AND "
+		       .       "rs.computerid = $rscid AND "
+		       .       "rq.laststateid = ls.id AND "
+		       .       "rq.stateid = cs.id AND "
+		       .       "ls.name = 'tovmhostinuse' AND "
+		       .       "cs.name NOT IN ('failed', 'maintenance', 'complete', 'deleted') AND "
+		       .       "rq.end > NOW() "
+		       . "ORDER BY rq.start "
+		       . "LIMIT 1";
+		$qh = doQuery($query);
+		if($row = mysql_fetch_assoc($qh)) {
+			$cdata = $this->basecdata;
+			$cdata['compid'] = $rscid;
+			$cont = addContinuationsEntry('AJcanceltovmhostinuse', $cdata, 300, 1, 0);
+			$this->jsondata['tohostcancelcont'] = $cont;
+			$this->jsondata['showcancel'] = 1;
+			$this->jsondata['tohoststart'] = date('g:i A \o\n l, F jS, Y', $row['start']);
+			if($row['start'] > time())
+				$this->jsondata['tohostfuture'] = 1;
+			else
+				$this->jsondata['tohostfuture'] = 0;
+		}
+		parent::AJeditResource();
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn AJsaveResource()
+	///
+	/// \brief saves changes to resource
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function AJsaveResource() {
+		global $user;
+		$add = getContinuationVar('add', 0);
+		$data = $this->validateResourceData();
+		if($data['error']) {
+			$ret = array('status' => 'error', 'msg' => $data['errormsg']);
+			sendJSON($ret);
+			return;
+		}
+
+		$promptuser = 0;
+		$promptuserfail = 0;
+		$multirefresh = 0;
+
+		if($add) {
+			if(! $data['rscid'] = $this->addResource($data)) {
+				sendJSON(array('status' => 'adderror',
+				               'errormsg' => 'Error encountered while trying to create new computer(s).<br>Please contact an admin for assistance.'));
+				return;
+			}
+		}
+		else {
+			$olddata = getContinuationVar('olddata');
+			$updates = array();
+			# hostname
+			if($data['name'] != $olddata['hostname'])
+				$updates[] = "hostname = '{$data['name']}'";
+
+			# ownerid
+			$ownerid = getUserlistID($data['owner']);
+			if($ownerid != $olddata['ownerid'])
+				$updates[] = "ownerid = $ownerid";
+
+			# cores
+			if($data['cores'] != $olddata['procnumber'])
+				$updates[] = "procnumber = '{$data['cores']}'";
+
+			# eth0macaddress
+			if($data['eth0macaddress'] != $olddata['eth0macaddress']) {
+				if($data['eth0macaddress'] == '')
+					$updates[] = "eth0macaddress = NULL";
+				else
+					$updates[] = "eth0macaddress = '{$data['eth0macaddress']}'";
+			}
+
+			# eth1macaddress
+			if($data['eth1macaddress'] != $olddata['eth1macaddress']) {
+				if($data['eth1macaddress'] == '')
+					$updates[] = "eth1macaddress = NULL";
+				else
+					$updates[] = "eth1macaddress = '{$data['eth1macaddress']}'";
+			}
+
+			# other fields
+			$fields = array('type', 'IPaddress', 'privateIPaddress',
+			                'provisioningid', 'platformid', 'scheduleid', 'ram',
+			                'procspeed', 'network', 'location');
+			foreach($fields as $field) {
+				if($data[$field] != $olddata[$field])
+					$updates[] = "`$field` = '{$data[$field]}'";
+			}
+
+			# notes
+			# staying in maintenance
+			if($olddata['stateid'] == 10 && $data['stateid'] == 10) {
+				$testnotes = $olddata['notes'];
+				# check for notes being changed
+				if(strpos($testnotes, '@') === true) {
+					$tmp = explode('@', $olddata['notes']);
+					$testnotes = $tmp[1];
+				}
+				if($testnotes != $data['notes']) {
+					$ts = unixToDatetime(time());
+					$updates[] = "notes = '{$user['unityid']} $ts@{$data['notes']}'";
+				}
+			}
+			# changing to maintenance
+			elseif($data['stateid'] == 10) {
+				$ts = unixToDatetime(time());
+				$updates[] = "notes = '{$user['unityid']} $ts@{$data['notes']}'";
+			}
+			# removing from maintenance
+			elseif($olddata['stateid'] == 10 && $data['stateid'] != 10) {
+				$updates[] = "notes = ''";
+			}
+
+			# stateid - if moving from vmhostinuse or reloading with a new image,
+			#           make sure no reservations for VMs
+			if($olddata['stateid'] == 10 && $data['stateid'] == 20) {
+				$query = "SELECT vm.id "
+				       . "FROM computer vm, "
+				       .      "vmhost v "
+				       . "WHERE v.computerid = {$data['rscid']} AND "
+				       .       "vm.vmhostid = v.id AND "
+				       .       "vm.notes = 'maintenance with host {$data['rscid']}' AND "
+				       .       "vm.stateid = 10";
+				$qh = doQuery($query);
+				$vmids = array();
+				while($row = mysql_fetch_assoc($qh))
+					$vmids[] = $row['id'];
+				$allids = implode(',', $vmids);
+				if($data['provisioning'] != 'none')  {
+					$profiles = getVMProfiles();
+					if(! array_key_exists('vmprofileid', $olddata) ||
+						$olddata['vmprofileid'] == '' || 
+					   $profiles[$olddata['vmprofileid']]['imageid'] !=
+						$profiles[$data['vmprofileid']]['imageid']) {
+						# VCL provisioned, different image
+						# schedule VM host to be reloaded
+						$profiles = getVMProfiles($data['vmprofileid']);
+						$imageid = $profiles[$data['vmprofileid']]['imageid'];
+						$start = getReloadStartTime();
+						$rc = $this->scheduleTovmhostinuse($data['rscid'], $imageid, $start,
+						                                   $data['vmprofileid'], $olddata['vmprofileid']);
+	
+						if($rc == 0) {
+							$msg = '';
+							if(count($updates))
+								$msg .= "Computer information changes were saved.<br>\nHowever, a ";
+							else
+								$msg .= "A ";
+							$msg .= "problem was encountered while attempting to reload the ";
+							$msg .= "computer with the selected VM Host Profile. Please try ";
+							$msg .= "again at a later time.\n";
+							$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+							$promptuserfail = 1;
+							$title = 'VM Host Reload Failed';
+						}
+						else {
+							if(count($vmids))
+								$this->scheduleVMsToAvailable($vmids);
+							$multirefresh = 3;
+						}
+					}
+					else {
+						# VCL provisioned, same image
+						$msg = '';
+						if(count($updates))
+							$msg .= "Computer information changes saved.<br><br>\nHowever, this ";
+						else
+							$msg .= "This ";
+						$msg .= "computer was previously in the vmhostinuse state. ";
+						$msg .= "You can:<br><br>\n";
+						$msg .= "<input type=\"radio\" name=\"mode\" value=\"vmhostinuse\" ";
+						$msg .= "id=\"modedirect\" checked=\"checked\"><label ";
+						$msg .= "for=\"modereload\">Move it directly back to vmhostinuse\n";
+						$msg .= "</label><br>\n";
+						$msg .= "<input type=\"radio\" name=\"mode\" value=\"reload\" ";
+						$msg .= "id=\"modereload\"><label for=\"modereload\">Have it reloaded ";
+						$msg .= "and then placed back into vmhostinuse</label><br><br>\n";
+						$promptuser = 1;
+						$cdata = $this->basecdata;
+						$cdata['compid'] = $data['rscid'];
+						$cdata['imageid'] = $profiles[$data['vmprofileid']]['imageid'];
+						$cdata['oldprofileid'] = $olddata['vmprofileid'];
+						$cdata['vmprofileid'] = $data['vmprofileid'];
+						$cdata['newstateid'] = $data['stateid'];
+						$cdata['oldstateid'] = $olddata['stateid'];
+						$cdata['vmids'] = $vmids;
+						$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
+						$btntxt = 'Submit';
+						$title = 'State Change Option';
+					}
+					$data['stateid'] = $olddata['stateid']; # prevent state from being updated directly
+				}
+				elseif(count($vmids)) {
+					$query = "UPDATE computer "
+					       . "SET stateid = 2, "
+					       .     "notes = '' "
+							 . "WHERE id in ($allids)";
+					doQuery($query);
+					$multirefresh = 1;
+				}
+			}
+			elseif($olddata['stateid'] != 20 && $data['stateid'] == 20) {
+				# check for reservations
+				moveReservationsOffComputer($data['rscid']);
+				cleanSemaphore();
+				$reloadstart = getCompFinalReservationTime($data['rscid'], 21);
+				$checkstart = getExistingChangeStateStartTime($data['rscid'], 21);
+				if($data['provisioning'] != 'none')  {
+					# VCL provisioned
+					$profiles = getVMProfiles($data['vmprofileid']);
+					$imageid = $profiles[$data['vmprofileid']]['imageid'];
+					if($reloadstart) {
+						if($checkstart && $checkstart < $reloadstart)
+							$reloadstart = $checkstart;
+						# reservations, must wait until end time
+						$end = date('n/j/y g:i a', $reloadstart);
+						$msg = '';
+						if(count($updates))
+							$msg .= "Computer information changes saved.<br>\nHowever, this ";
+						else
+							$msg .= "This ";
+						$msg .= "computer is currently allocated until $end and cannot ";
+						$msg .= "be reloaded until then. You can:\n";
+						$msg .= "<ul><li>Cancel and try later</li>\n";
+						$msg .= "<li>Schedule the computer to be reloaded with the selected ";
+						$msg .= "profile at $end</li></ul>\n";
+						$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+						$msg = preg_replace("|$end|", "<strong>$end</strong>", $msg, 1);
+						$promptuser = 1;
+						$cdata = $this->basecdata;
+						$cdata['maintenanceonly'] = 0;
+						$cdata['compid'] = $data['rscid'];
+						$cdata['reloadstart'] = $reloadstart;
+						$cdata['imageid'] = $imageid;
+						$cdata['oldprofileid'] = $olddata['vmprofileid'];
+						$cdata['vmprofileid'] = $data['vmprofileid'];
+						$cdata['newstateid'] = $data['stateid'];
+						$cdata['oldstateid'] = $olddata['stateid'];
+						$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
+						$btntxt = 'Schedule Reload';
+						$title = 'Delayed State Change';
+					}
+					else {
+						# no reservations
+						$start = getReloadStartTime();
+						$checkstart = getExistingChangeStateStartTime($data['rscid'], 21);
+						if($checkstart && $checkstart < $start)
+							$start = $checkstart;
+						$rc = $this->scheduleTovmhostinuse($data['rscid'], $imageid, $start,
+						                                   $data['vmprofileid'], $olddata['vmprofileid']);
+	
+						if($rc == 0) {
+							$msg = '';
+							if(count($updates))
+								$msg .= "Computer information changes were saved.<br>\nHowever, a ";
+							else
+								$msg .= "A ";
+							$msg .= "problem was encountered while attempting to reload the ";
+							$msg .= "computer with the selected VM Host Profile. Please try ";
+							$msg .= "again at a later time.\n";
+							$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+							$promptuserfail = 1;
+							$title = 'VM Host Reload Failed';
+						}
+						else
+							$multirefresh = 3;
+					}
+					$data['stateid'] = $olddata['stateid']; # prevent state from being updated directly
+				}
+				else {
+					# manually provisioned
+					if($reloadstart) {
+						# reservations, must wait until end time
+						$end = date('n/j/y g:i a', $reloadstart);
+						$msg = '';
+						if(count($updates))
+							$msg .= "Computer information changes saved.<br>\nHowever, this ";
+						else
+							$msg .= "This ";
+						$msg .= "computer is currently allocated until $end and cannot ";
+						$msg .= "be converted to a VM host until then. You can:\n";
+						$msg .= "<ul><li>Cancel and do nothing</li>\n";
+						$msg .= "<li>Schedule the computer to go in to maintenance at $end ";
+						$msg .= "and manually move it to vmhostinuse after that</li></ul>\n";
+						$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+						$msg = preg_replace("|$end|", "<strong>$end</strong>", $msg, 1);
+						$promptuser = 1;
+						$cdata = $this->basecdata;
+						$cdata['maintenanceonly'] = 1;
+						$cdata['reloadstart'] = $reloadstart;
+						$cdata['imageid'] = getImageId('noimage');
+						$cdata['compid'] = $data['rscid'];
+						$cdata['newstateid'] = $data['stateid'];
+						$cdata['oldstateid'] = $olddata['stateid'];
+						$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
+						$btntxt = 'Schedule State Change';
+						$title = 'Delayed State Change';
+						$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
+					}
+					else {
+						# no reservations
+						$this->updateVmhostProfile($data['rscid'], $data['vmprofileid'], $olddata['vmprofileid']);
+					}
+				}
+			}
+			elseif($olddata['stateid'] == 20 && $data['stateid'] == 2) {
+				# only valid condition for VCL provisioned
+				# check for reservations
+				moveReservationsOffVMs($data['rscid']);
+				cleanSemaphore();
+				$reloadstart = getCompFinalVMReservationTime($data['rscid'], 1);
+				if($reloadstart == -1) {
+					$msg = '';
+					if(count($updates))
+						$msg .= "Computer information changes were saved.<br>\nHowever, a ";
+					else
+						$msg .= "A ";
+					$msg .= "problem was encountered while attempting to move VMs ";
+					$msg .= "off of the computer. Please try again at a later time.\n";
+					$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+					$promptuserfail = 1;
+					$title = 'Change to Available Failed';
+					$data['stateid'] = $olddata['stateid'];
+				}
+				elseif($reloadstart > 0) {
+					cleanSemaphore();
+					$end = date('n/j/y g:i a', $reloadstart);
+					$msg = '';
+					if(count($updates))
+						$msg .= "Computer information changes saved.<br>\nHowever, this ";
+					else
+						$msg .= "This ";
+					$msg .= "computer currently has VMs with reservations on them until ";
+					$msg .= "$end and cannot be moved to the available state until then. ";
+					$msg .= "You can:\n";
+					$msg .= "<ul><li>Cancel and do nothing</li>\n";
+					$msg .= "<li>Schedule the VMs to be removed at $end and the computer ";
+					$msg .= "to be moved to available that</li></ul>\n";
+					$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+					$msg = preg_replace("|$end|", "<strong>$end</strong>", $msg, 1);
+					$promptuser = 1;
+					$cdata = $this->basecdata;
+					$cdata['reloadstart'] = $reloadstart;
+					$cdata['imageid'] = getImageId('noimage');
+					$cdata['compid'] = $data['rscid'];
+					$cdata['newstateid'] = $data['stateid'];
+					$cdata['oldstateid'] = $olddata['stateid'];
+					$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
+					$btntxt = 'Schedule State Change';
+					$title = 'Delayed State Change';
+					$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
+				}
+				else {
+					# schedule tomaintenance reservations for VMs
+					#   might be better to just directly move the VMs to the maintenance state
+					$vclreloadid = getUserlistID('vclreload@Local');
+					$imageid = getImageId('noimage');
+					$revid = getProductionRevisionid($imageid);
+					$start = getReloadStartTime();
+					$end = $start + SECINMONTH;
+					$startdt = unixToDatetime($start);
+					$enddt = unixToDatetime($end);
+					$query = "SELECT vm.id "
+					       . "FROM computer vm, "
+					       .      "vmhost v "
+					       . "WHERE v.computerid = {$data['rscid']} AND "
+					       .       "vm.vmhostid = v.id";
+					$qh = doQuery($query);
+					$fail = 0;
+					while($row = mysql_fetch_assoc($qh)) {
+						if(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
+						                      $enddt, 18, $vclreloadid)) {
+							$fail = 1;
+							break;
+						}
+						else
+							$multirefresh = 2;
+					}
+					cleanSemaphore();
+					if($fail) {
+						$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
+						$msg = '';
+						if(count($updates))
+							$msg .= "Computer information changes were saved.<br>\nHowever, a ";
+						else
+							$msg .= "A ";
+						$msg .= "problem was encountered while attempting to remove VMs ";
+						$msg .= "from the computer. Please try again at a later time.\n";
+						$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+						$promptuserfail = 1;
+						$title = 'Change State to Available Failed';
+					}
+				}
+			}
+			elseif($olddata['stateid'] == 20 && $data['stateid'] == 10) {
+				# VCL provisioned and manually provisioned are the same
+				# check for reservations
+				moveReservationsOffVMs($data['rscid']);
+				cleanSemaphore();
+				$reloadstart = getCompFinalVMReservationTime($data['rscid'], 1, 1);
+				if($reloadstart == -1) {
+					$msg = '';
+					if(count($updates))
+						$msg .= "Computer information changes were saved.<br>\nHowever, a ";
+					else
+						$msg .= "A ";
+					$msg .= "problem was encountered while attempting to place assigned VMs ";
+					$msg .= "into the maintenance state. Please try again at a later time.\n";
+					$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+					$promptuserfail = 1;
+					$title = 'Change to Maintenance Failed';
+				}
+				elseif($reloadstart > 0) {
+					cleanSemaphore();
+					$end = date('n/j/y g:i a', $reloadstart);
+					$msg = '';
+					if(count($updates))
+						$msg .= "Computer information changes saved.<br>\nHowever, this ";
+					else
+					$msg .= "This ";
+					$msg .= "computer currently has VMs with reservations on them until ";
+					$msg .= "$end and cannot be moved to the maintenance state until then. ";
+					$msg .= "You can:\n";
+					$msg .= "<ul><li>Cancel and do nothing</li>\n";
+					$msg .= "<li>Schedule the computer and VMs to be moved into the ";
+					$msg .= "maintenance state at $end</li></ul>\n";
+					$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+					$msg = preg_replace("|$end|", "<strong>$end</strong>", $msg, 1);
+					$promptuser = 1;
+					$cdata = $this->basecdata;
+					$cdata['reloadstart'] = $reloadstart;
+					$cdata['imageid'] = getImageId('noimage');
+					$cdata['compid'] = $data['rscid'];
+					$cdata['newstateid'] = $data['stateid'];
+					$cdata['oldstateid'] = $olddata['stateid'];
+					$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
+					$btntxt = 'Schedule State Change';
+					$title = 'Delayed State Change';
+					$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
+				}
+				else {
+					$query = "UPDATE computer c "
+					       . "INNER JOIN vmhost v ON (c.vmhostid = v.id) "
+					       . "SET c.stateid = 10, "
+					       .     "c.notes = 'maintenance with host {$data['rscid']}' "
+					       . "WHERE v.computerid = {$data['rscid']}";
+					doQuery($query);
+					cleanSemaphore();
+					$multirefresh = 1;
+				}
+			}
+			elseif($olddata['stateid'] == 10 && $data['stateid'] == 2) {
+				if(is_numeric($olddata['vmprofileid'])) {
+					$vclreloadid = getUserlistID('vclreload@Local');
+					$imageid = getImageId('noimage');
+					$revid = getProductionRevisionid($imageid);
+					$start = getReloadStartTime();
+					$end = $start + SECINMONTH;
+					$startdt = unixToDatetime($start);
+					$enddt = unixToDatetime($end);
+					# move VMs to reload state so vcld will not skip them due to being in maintenance
+					$query = "UPDATE computer c, "
+					       .        "vmhost v "
+					       . "SET c.stateid = 19, "
+					       .     "c.notes = '' "
+					       . "WHERE v.computerid = {$data['rscid']} AND "
+					       .       "c.vmhostid = v.id";
+					doQuery($query);
+					$query = "SELECT vm.id "
+					       . "FROM computer vm, "
+					       .      "vmhost v "
+					       . "WHERE v.computerid = {$data['rscid']} AND "
+					       .       "vm.vmhostid = v.id";
+					$qh = doQuery($query);
+					$fails = array();
+					while($row = mysql_fetch_assoc($qh)) {
+						if(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
+						                      $enddt, 18, $vclreloadid)) {
+							$fails[] = $row['id'];
+						}
+						else
+							$multirefresh = 2;
+					}
+					if(count($fails)) {
+						# just directly remove any VMs that failed to be scheduled
+						$query = "UPDATE computer "
+						       . "SET stateid = 10, "
+						       .     "vmhostid = NULL, "
+						       .     "notes = '' "
+						       . "WHERE id IN (" . implode(',', $fails) . ")";
+						doQuery($query);
+					}
+				}
+			}
+			elseif($olddata['stateid'] == 20 && $data['stateid'] == 20 &&
+			       $olddata['vmprofileid'] != $data['vmprofileid']) {
+				if($data['provisioning'] != 'none')  {
+					$profiles = getVMProfiles($data['vmprofileid']);
+					if($profiles[$olddata['vmprofileid']]['imageid'] ==
+					   $profiles[$data['vmprofileid']]['imageid']) {
+						$query = "UPDATE vmhost "
+						       . "SET vmprofileid = {$data['vmprofileid']} "
+						       . "WHERE computerid = {$data['rscid']} AND "
+						       .       "vmprofileid = {$olddata['vmprofileid']}";
+						doQuery($query);
+					}
+					else {
+						moveReservationsOffVMs($data['rscid']);
+						cleanSemaphore();
+						$reloadstart = getCompFinalVMReservationTime($data['rscid'], 1);
+						if($reloadstart == -1) {
+							$msg = '';
+							if(count($updates))
+								$msg .= "Computer information changes were saved.<br>\nHowever, a ";
+							else
+								$msg .= "A ";
+							$msg .= "problem was encountered while attempting to place assigned ";
+							$msg .= "VMs into the maintenance state while reloading the computer. ";
+							$msg .= "Please try again at a later time.\n";
+							$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+							$promptuserfail = 1;
+							$title = 'Change VM Host Profile Failed';
+						}
+						elseif($reloadstart > 0) {
+							cleanSemaphore();
+							$end = date('n/j/y g:i a', $reloadstart);
+							$msg = '';
+							if(count($updates))
+								$msg .= "Computer information changes saved.<br>\nHowever, this ";
+							else
+								$msg .= "This ";
+							$msg .= "computer must be reloaded to change to the selected VM Host ";
+							$msg .= "Profile and there are VMs on it with reservations until $end. ";
+							$msg .= "You can:\n";
+							$msg .= "<ul><li>Cancel and do nothing</li>\n";
+							$msg .= "<li>Schedule the VMs to be removed and the computer to be ";
+							$msg .= "reloaded at $end</li></ul>\n";
+							$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+							$msg = preg_replace("|$end|", "<strong>$end</strong>", $msg, 1);
+							$promptuser = 1;
+							$cdata = $this->basecdata;
+							$cdata['reloadstart'] = $reloadstart;
+							$cdata['imageid'] = $profiles[$data['vmprofileid']]['imageid'];
+							$cdata['compid'] = $data['rscid'];
+							$cdata['newstateid'] = $data['stateid'];
+							$cdata['oldstateid'] = $olddata['stateid'];
+							$cdata['oldprofileid'] = $olddata['vmprofileid'];
+							$cdata['vmprofileid'] = $data['vmprofileid'];
+							$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
+							$btntxt = 'Schedule Reload';
+							$title = 'Delayed VM Host Profile Change';
+						}
+						else {
+							# schedule VMs to be removed
+							$vclreloadid = getUserlistID('vclreload@Local');
+							$imageid = getImageId('noimage');
+							$revid = getProductionRevisionid($imageid);
+							$start = getReloadStartTime();
+							$end = $start + SECINMONTH;
+							$startdt = unixToDatetime($start);
+							$enddt = unixToDatetime($end);
+							$query = "SELECT vm.id "
+							       . "FROM computer vm, "
+							       .      "vmhost v "
+							       . "WHERE v.computerid = {$data['rscid']} AND "
+							       .       "vm.vmhostid = v.id";
+							$qh = doQuery($query);
+							$fails = array();
+							$cnt = 0;
+							while($row = mysql_fetch_assoc($qh)) {
+								$cnt++;
+								if(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
+								                      $enddt, 18, $vclreloadid)) {
+									$fails[] = $row['id'];
+								}
+							}
+							if(count($fails)) {
+								# just directly remove any VMs that failed to be scheduled
+								$query = "UPDATE computer "
+								       . "SET stateid = 10, "
+								       .     "vmhostid = NULL, "
+								       .     "notes = '' "
+								       . "WHERE id IN (" . implode(',', $fails) . ")";
+								doQuery($query);
+							}
+							cleanSemaphore();
+
+							# schedule host to be reloaded
+							if($cnt)
+								$start = time() + 120; # allow 2 minutes for VMs to be removed
+							$rc = $this->scheduleTovmhostinuse($data['rscid'],
+							                                   $profiles[$data['vmprofileid']]['imageid'],
+							                                   $start, $data['vmprofileid'],
+							                                   $olddata['vmprofileid']);
+
+							if($rc == 0) {
+								$msg = '';
+								if(count($updates))
+									$msg .= "Computer information changes were saved.<br>\nHowever, a ";
+								else
+									$msg .= "A ";
+								$msg .= "problem was encountered while attempting to reload the ";
+								$msg .= "computer with the selected VM Host Profile. Please try ";
+								$msg .= "again at a later time.\n";
+								$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+								$promptuserfail = 1;
+								$title = 'VM Host Reload Failed';
+							}
+							else
+								$multirefresh = 3;
+						}
+					}
+				}
+				else {
+					$query = "UPDATE vmhost "
+					       . "SET vmprofileid = {$data['vmprofileid']} "
+					       . "WHERE computerid = {$data['rscid']} AND "
+					       .       "vmprofileid = {$olddata['vmprofileid']}";
+					doQuery($query);
+				}
+			}
+			elseif($olddata['stateid'] != 10 && $data['stateid'] == 10) {
+				moveReservationsOffComputer($data['rscid']);
+				cleanSemaphore();
+				$reloadstart = getCompFinalReservationTime($data['rscid']);
+				if($reloadstart) {
+					$end = date('n/j/y g:i a', $reloadstart);
+					$msg = '';
+					if(count($updates))
+						$msg .= "Computer information changes saved.<br>\nHowever, this ";
+					else
+						$msg .= "This ";
+					$msg .= "computer has reservations on it until $end. You can:\n";
+					$msg .= "<ul><li>Cancel and do nothing</li>\n";
+					$msg .= "<li>Schedule the computer to be moved to maintenance at ";
+					$msg .= "$end</li></ul>\n";
+					$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg);
+					$msg = preg_replace("|$end|", "<strong>$end</strong>", $msg, 1);
+					$promptuser = 1;
+					$cdata = $this->basecdata;
+					$cdata['reloadstart'] = $reloadstart;
+					$cdata['imageid'] = getImageId('noimage');
+					$cdata['compid'] = $data['rscid'];
+					$cdata['newstateid'] = $data['stateid'];
+					$cdata['oldstateid'] = $olddata['stateid'];
+					$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
+					$btntxt = 'Schedule Maintenance';
+					$title = 'Delayed Maintenance';
+				}
+				# else let UPDATE move it to maintenance
+			}
+
+			# stateid
+			if($data['stateid'] != $olddata['stateid'])
+				$updates[] = "stateid = {$data['stateid']}";
+
+			if(count($updates)) {
+				$query = "UPDATE computer SET "
+				       . implode(', ', $updates)
+				       . " WHERE id = {$data['rscid']}";
+				doQuery($query);
+			}
+		}
+
+		# clear user resource cache for this type
+		$key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 1, 0));
+		unset($_SESSION['userresources'][$key]);
+		$key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 0, 0));
+		unset($_SESSION['userresources'][$key]);
+		$key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 0, 1, 0));
+		unset($_SESSION['userresources'][$key]);
+		$key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 0, 0, 0));
+		unset($_SESSION['userresources'][$key]);
+
+		$args = $this->defaultGetDataArgs;
+		$arr = array('status' => 'success');
+		if(is_array($data['rscid'])) {
+			$tmp = $this->getData($args);
+			$arr['addmode'] = 'multiple';
+			$arr['data'] = array();
+			foreach($data['rscid'] as $compid) {
+				$tmp[$compid]['name'] = $tmp[$compid]['hostname'];
+				$arr['data'][] = $tmp[$compid];
+			}
+			$arr['grouphelp'] = "Select groups from the list on the right and click the "
+			                  . "Add button to add the new computer set to those groups.<br><br>";
+			$cdata = $this->basecdata;
+			$cdata['newids'] = $data['rscid'];
+			$cdata['mode'] = 'add';
+			$arr['addcont'] = addContinuationsEntry('AJaddRemGroupResource', $cdata);
+			$cdata['mode'] = 'remove';
+			$arr['remcont'] = addContinuationsEntry('AJaddRemGroupResource', $cdata);
+		}
+		else {
+			if($add)
+				$arr['addmode'] = 'single';
+			$args['rscid'] = $data['rscid'];
+			$tmp = $this->getData($args);
+			$data = $tmp[$data['rscid']];
+			$arr['data'] = $data;
+			$arr['data']['name'] = $arr['data']['hostname'];
+		}
+		if($add) {
+			$arr['action'] = 'add';
+			$arr['nogroups'] = 0;
+			$groups = getUserResources(array($this->restype . 'Admin'), array('manageGroup'), 1);
+			if(count($groups[$this->restype]))
+				$arr['groupingHTML'] = $this->groupByResourceHTML();
+			else
+				$arr['nogroups'] = 1;
+		}
+		else
+			$arr['action'] = 'edit';
+		if($promptuser) {
+			$arr['promptuser'] = 1;
+			$arr['btntxt'] = $btntxt;
+			$arr['title'] = $title;
+			$arr['msg'] = $msg;
+			$arr['cont'] = $promptcont;
+		}
+		elseif($promptuserfail) {
+			$arr['promptuserfail'] = 1;
+			$arr['title'] = $title;
+			$arr['msg'] = $msg;
+		}
+		if($multirefresh)
+			$arr['multirefresh'] = $multirefresh;
+		sendJSON($arr);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn validateResourceData()
+	///
+	/// \return array with these fields:\n
+	/// \b rscid - id of resource (from computer table)\n
+	/// \b name - hostname of computer\n
+	/// \b startnum - start number when doing multiple add\n
+	/// \b endnum - end number when doing multiple add\n
+	/// \b owner\n
+	/// \b type - type of computer\n
+	/// \b IPaddress - public IP address\n
+	/// \b privateIPaddress - private IP address\n
+	/// \b eth0macaddress - public MAC address\n
+	/// \b eth1macaddress - private MAC address\n
+	/// \b startpubipaddress - start public IP address when doing multiple add\n
+	/// \b endpubipaddress - end public IP address when doing multiple add\n
+	/// \b startprivipaddress - start private IP address when doing multiple
+	///    add\n
+	/// \b endprivipaddress - end private IP address when doing multiple add\n
+	/// \b startmac - start MAC address when doing multiple add\n
+	/// \b provisioningid - id of provisioning engine for computer(s)\n
+	/// \b stateid - id for state of computer\n
+	/// \b notes - maintenance notes when setting computer to maintenance state\n
+	/// \b vmprofileid - id of vmprofile when setting to vmhostinuse state\n
+	/// \b platformid - id of platform\n
+	/// \b scheduleid - id of schedule\n
+	/// \b ram\n
+	/// \b cores\n
+	/// \b procspeed\n
+	/// \b network\n
+	/// \b location - free string describing location\n
+	/// \b mode - 'edit' or 'add'\n
+	/// \b addmode - 'single' or 'multiple'\n
+	/// \b startpubiplong - numeric value for start public IP address when doing
+	///    multiple add\n
+	/// \b endpubiplong - numeric value for end public IP address when doing
+	///    multiple add\n
+	/// \b startpriviplong - numeric value for start private IP address when
+	///    doing multiple add\n
+	/// \b endpriviplong - numeric value for end private IP address when doing
+	///    multiple add\n
+	/// \b error - 0 if submitted data validates; 1 if anything is invalid\n
+	/// \b errormsg - if error = 1; string of error messages separated by html
+	///    break tags
+	///
+	/// \brief validates form input from editing or adding a computer
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function validateResourceData() {
+		global $user;
+
+		$return = array('error' => 0);
+
+		$return['rscid'] = getContinuationVar('rscid', 0);
+		$return['name'] = processInputVar('name', ARG_STRING);
+		$return['startnum'] = processInputVar('startnum', ARG_NUMERIC);
+		$return['endnum'] = processInputVar('endnum', ARG_NUMERIC);
+		$return['owner'] = processInputVar('owner', ARG_STRING, "{$user['unityid']}@{$user['affiliation']}");
+		$return['type'] = processInputVar('type', ARG_STRING);
+		$return['IPaddress'] = processInputVar('ipaddress', ARG_STRING);
+		$return['privateIPaddress'] = processInputVar('privateipaddress', ARG_STRING);
+		$return['eth0macaddress'] = processInputVar('privatemac', ARG_STRING);
+		$return['eth1macaddress'] = processInputVar('publicmac', ARG_STRING);
+		$return['startpubipaddress'] = processInputVar('startpubipaddress', ARG_STRING);
+		$return['endpubipaddress'] = processInputVar('endpubipaddress', ARG_STRING);
+		$return['startprivipaddress'] = processInputVar('startprivipaddress', ARG_STRING);
+		$return['endprivipaddress'] = processInputVar('endprivipaddress', ARG_STRING);
+		$return['startmac'] = processInputVar('startmac', ARG_STRING);
+		$return['provisioningid'] = processInputVar('provisioningid', ARG_NUMERIC);
+		$return['stateid'] = processInputVar('stateid', ARG_NUMERIC);
+		$return['notes'] = processInputVar('notes', ARG_STRING);
+		$return['vmprofileid'] = processInputVar('vmprofileid', ARG_NUMERIC);
+		$return['platformid'] = processInputVar('platformid', ARG_NUMERIC);
+		$return['scheduleid'] = processInputVar('scheduleid', ARG_NUMERIC);
+		$return['ram'] = processInputVar('ram', ARG_NUMERIC);
+		$return['cores'] = processInputVar('cores', ARG_NUMERIC);
+		$return['procspeed'] = processInputVar('procspeed', ARG_NUMERIC);
+		$return['network'] = processInputVar('network', ARG_NUMERIC);
+		$return['location'] = processInputVar('location', ARG_STRING);
+		$addmode = processInputVar('addmode', ARG_STRING);
+
+		if(! is_null($addmode) && $addmode != 'single' && $addmode != 'multiple') {
+			$return['error'] = 1;
+			$return['errormsg'] = "Invalid Add mode submitted";
+			return $return;
+		}
+
+		$olddata = getContinuationVar('olddata');
+
+		if($return['rscid'] == 0)
+			$return['mode'] = 'add';
+		else
+			$return['mode'] = 'edit';
+
+		$errormsg = array();
+
+		# hostname
+		$hostreg = '/^[a-zA-Z0-9_][-a-zA-Z0-9_\.]{1,49}$/';
+		if($return['mode'] == 'add' && $addmode == 'multiple')
+			$hostreg = '/^[a-zA-Z0-9_%][-a-zA-Z0-9_\.%]{1,49}$/';
+		if(! preg_match($hostreg, $return['name'])) {
+			$return['error'] = 1;
+			$errormsg[] = "Hostname can only contain letters, numbers, dashes(-), periods(.), and underscores(_). It can be from 1 to 50 characters long";
+		}
+		elseif($this->checkForHostname($return['name'], $return['rscid'])) {
+			$return['error'] = 1;
+			$errormsg[] = "A computer already exists with this hostname.";
+		}
+		# add multiple
+		if($return['mode'] == 'add' && $addmode == 'multiple') {
+			# startnum/endnum
+			if($return['startnum'] < 0 || $return['startnum'] > 255) {
+				$return['error'] = 1;
+				$errormsg[] = "Start must be from 0 to 255";
+			}
+			if($return['endnum'] < 0 || $return['endnum'] > 255) {
+				$return['error'] = 1;
+				$errormsg[] = "End must be from 0 to 255";
+			}
+			if($return['startnum'] >= 0 && $return['startnum'] <= 255 &&
+			   $return['endnum'] >= 0 && $return['endnum'] <= 255 &&
+			   $return['startnum'] > $return['endnum']) {
+				$return['error'] = 1;
+				$errormsg[] = "Start must be &gt;= End";
+			}
+			$checkhosts = array();
+			for($i = $return['startnum']; $i <= $return['endnum']; $i++)
+				$checkhosts[] = str_replace('%', $i, $return['name']);
+			$allhosts = implode("','", $checkhosts);
+			$query = "SELECT hostname FROM computer "
+			       . "WHERE hostname IN ('$allhosts') AND "
+			       .       "deleted = 0";
+			$qh = doQuery($query);
+			$exists = array();
+			while($row = mysql_fetch_assoc($qh))
+				$exists[] = $row['hostname'];
+			if(count($exists)) {
+				$hosts = implode(', ', $exists);
+				$return['error'] = 1;
+				$errormsg[] = "There are already computers with these hostnames: $hosts";
+			}
+		}
+		else {
+			$return['startnum'] = 0;
+			$return['endnum'] = 0;
+		}
+		# owner
+		if(! validateUserid($return['owner'])) {
+			$return['error'] = 1;
+			$errormsg[] = "Submitted owner is not valid";
+		}
+		# type
+		if(! preg_match('/^(blade|lab|virtualmachine)$/', $return['type'])) {
+			$return['error'] = 1;
+			$errormsg[] = "Submitted type is not valid";
+		}
+		# edit or add single
+		if($return['rscid'] || ($return['mode'] == 'add' && $addmode == 'single')) {
+			# ipaddress
+			if(! validateIPv4addr($return['IPaddress'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Invalid Public IP address. Must be w.x.y.z with each of "
+			               . "w, x, y, and z being between 1 and 255 (inclusive)";
+			}
+			# private ipaddress
+			if(strlen($return['privateIPaddress']) &&
+			   ! validateIPv4addr($return['privateIPaddress'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Invalid Private IP address. Must be w.x.y.z with each of "
+			               . "w, x, y, and z being between 1 and 255 (inclusive)";
+			}
+			# eth0macaddress
+			if(strlen($return['eth0macaddress'])) {
+				if(! preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $return["eth0macaddress"])) {
+					$return['error'] = 1;
+					$errormsg[] = "Invalid Private MAC address. Must be XX:XX:XX:XX:XX:XX "
+					            . "with each pair of XX being from 00 to FF (inclusive)";
+				}
+				elseif($this->checkForMACaddress($return['eth0macaddress'], 0, $return['rscid'])) {
+					$return['error'] = 1;
+					$errormsg[] = "There is already a computer with this Private MAC address.";
+				}
+			}
+			# eth1macaddress
+			if(strlen($return['eth1macaddress'])) {
+				if(! preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $return["eth1macaddress"])) {
+					$return['error'] = 1;
+					$errormsg[] = "Invalid Public MAC address. Must be XX:XX:XX:XX:XX:XX "
+					            . "with each pair of XX being from 00 to FF (inclusive)";
+				}
+				elseif($this->checkForMACaddress($return['eth1macaddress'], 1, $return['rscid'])) {
+					$return['error'] = 1;
+					$errormsg[] = "There is already a computer with this Public MAC address.";
+				}
+			}
+		}
+		else {
+			$return['IPaddress'] = '';
+			$return['privateIPaddress'] = '';
+			$return['eth0macaddress'] = '';
+			$return['eth1macaddress'] = '';
+		}
+		# add multiple
+		if($return['mode'] == 'add' && $addmode == 'multiple') {
+			if(! validateIPv4addr($return['startpubipaddress'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Invalid Start Public IP address. Must be w.x.y.z with each of "
+			               . "w, x, y, and z being between 1 and 255 (inclusive)";
+			}
+			if(! validateIPv4addr($return['endpubipaddress'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Invalid End Public IP address. Must be w.x.y.z with each of "
+			               . "w, x, y, and z being between 1 and 255 (inclusive)";
+			}
+			if(! validateIPv4addr($return['startprivipaddress'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Invalid Start Private IP address. Must be w.x.y.z with each of "
+			               . "w, x, y, and z being between 1 and 255 (inclusive)";
+			}
+			if(! validateIPv4addr($return['endprivipaddress'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Invalid End Private IP address. Must be w.x.y.z with each of "
+			               . "w, x, y, and z being between 1 and 255 (inclusive)";
+			}
+			$startpubiplong = ip2long($return['startpubipaddress']);
+			$endpubiplong = ip2long($return['endpubipaddress']);
+			if($startpubiplong > $endpubiplong) {
+				$return['error'] = 1;
+				$errormsg[] = "Start Public IP Address must be lower or equal to End Public IP Address";
+			}
+			elseif(($endpubiplong - $startpubiplong) != ($return['endnum'] - $return['startnum'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Public IP Address range does not equal Start/End range";
+			}
+			$startpriviplong = ip2long($return['startprivipaddress']);
+			$endpriviplong = ip2long($return['endprivipaddress']);
+			if($startpriviplong > $endpriviplong) {
+				$return['error'] = 1;
+				$errormsg[] = "Start Private IP Address must be lower or equal to End Private IP Address";
+			}
+			elseif(($endpriviplong - $startpriviplong) != ($return['endnum'] - $return['startnum'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Private IP Address range does not equal Start/End range";
+			}
+			$return['startpubiplong'] = $startpubiplong;
+			$return['endpubiplong'] = $endpubiplong;
+			$return['startpriviplong'] = $startpriviplong;
+			$return['endpriviplong'] = $endpriviplong;
+			$cnt = $endpubiplong - $startpubiplong + 1;
+			if($return['startmac'] != '') {
+				if(! preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $return['startmac'])) {
+					$return['error'] = 1;
+					$errormsg[] = "Invalid Start MAC address. Must be XX:XX:XX:XX:XX:XX "
+					            . "with each pair of XX being from 00 to FF (inclusive)";
+				}
+				elseif($this->checkMultiAddMacs($return['startmac'], $cnt, $msg, $macs)) {
+					$return['error'] = 1;
+					$errormsg[] = $msg;
+				}
+				$return['macs'] = $macs;
+			}
+			else
+				$return['macs'] = array();
+		}
+		else {
+			$return['startpubipaddress'] = '';
+			$return['endpubipaddress'] = '';
+			$return['startprivipaddress'] = '';
+			$return['endprivipaddress'] = '';
+			$return['startmac'] = '';
+		}
+		# provisioningid
+		$provisioning = getProvisioning();
+		if(! array_key_exists($return['provisioningid'], $provisioning)) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid Provisioning Engine selected";
+		}
+		else
+			$return['provisioning'] = $provisioning[$return['provisioningid']]['name'];
+		# stateid  2 - available, 10 - maintenance, 20 - vmhostinuse
+		if(! preg_match('/^(2|10|20)$/', $return['stateid']) &&
+		   $return['stateid'] != $olddata['stateid']) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for State";
+		}
+		# validate type/provisioning combinations
+		$provtypes = getProvisioningTypes();
+		if($olddata['provisioningid'] != $return['provisioningid'] &&
+		   ! array_key_exists($return['provisioningid'], $provtypes[$return['type']])) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid Provisioning Engine selected for computer type";
+		}
+		# validate type/provisioning/state combinations
+		if($olddata['stateid'] != $return['stateid']) {
+			if($return['type'] == 'lab') {
+				if($return['stateid'] != 2 && $return['stateid'] != 10) {
+					$return['error'] = 1;
+					$errormsg[] = "Invalid state submitted for computer type Lab";
+				}
+			}
+			elseif($return['type'] == 'virtualmachine') {
+				if($return['stateid'] != 10 &&
+				   (! is_numeric($olddata['vmhostid']) || $return['stateid'] != 2)) {
+					$return['error'] = 1;
+					$errormsg[] = "Invalid state submitted for computer type Virtual Machine";
+				}
+			}
+			elseif($return['type'] == 'blade') {
+				if($provisioning[$return['provisioningid']]['name'] == 'none' &&
+				   $return['stateid'] != 10 && $return['stateid'] != 20) {
+					$return['error'] = 1;
+					$errormsg[] = "Invalid state submitted for computer type Bare Metal";
+				}
+			}
+		}
+		# notes
+		if($return['stateid'] == 10) {
+			if(! preg_match('/^([-a-zA-Z0-9_\. ,#\(\)=\+:;]{0,5000})$/', $return['notes'])) {
+				$return['error'] = 1;
+				$errormsg[] = "Maintenance reason can be up to 5000 characters long and may only<br>contain letters, numbers, spaces and these characters: - , . _ # ( ) = + : ;";
+			}
+		}
+		else
+			$return['notes'] = '';
+		# vmprofileid
+		$profiles = getVMProfiles();
+		if($return['type'] == 'blade' && $return['stateid'] == 20 &&
+		   ! array_key_exists($return['vmprofileid'], $profiles)) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for VM Host Profile";
+		}
+		# platformid
+		$platforms = getPlatforms();
+		if(! array_key_exists($return['platformid'], $platforms)) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for Platform";
+		}
+		# scheduleid
+		$schedules = getSchedules();
+		if(! array_key_exists($return['scheduleid'], $schedules)) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for Schedule";
+		}
+		# ram
+		if($return['ram'] < 500 || $return['ram'] > 16777215) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for RAM";
+		}
+		# cores
+		if($return['cores'] < 1 || $return['cores'] > 255) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for No. Cores";
+		}
+		# procspeed
+		if($return['procspeed'] < 500 || $return['procspeed'] > 10000) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for Processor Speed";
+		}
+		# network
+		if(! preg_match('/^(10|100|1000|10000|100000)$/', $return['network'])) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for Network";
+		}
+		# location
+		if(! preg_match('/^([-a-zA-Z0-9_\. ,@#\(\)]{0,255})$/', $return['location'])) {
+			$return['error'] = 1;
+			$errormsg[] = "Invalid value submitted for Location";
+		}
+
+		if($return['mode'] == 'add')
+			$return['addmode'] = $addmode;
+
+		if($return['error'])
+			$return['errormsg'] = implode('<br>', $errormsg);
+
+		return $return;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn checkForHostname($hostname, $compid)
+	///
+	/// \param $hostname - a computer hostname
+	/// \param $compid - (optional) a computer id to ignore
+	///
+	/// \return 1 if $hostname is already in the computer table, 0 if not
+	///
+	/// \brief checks for $hostname being somewhere in the computer table except
+	/// for $compid
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function checkForHostname($hostname, $compid='') {
+		$query = "SELECT id FROM computer "
+		       . "WHERE hostname = '$hostname' AND "
+		       .       "deleted = 0";
+		if(! empty($compid))
+			$query .= " AND id != $compid";
+		$qh = doQuery($query);
+		if(mysql_num_rows($qh))
+			return 1;
+		return 0;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn checkForMACaddress($mac, $num, $compid)
+	///
+	/// \param $mac - computer mac address
+	/// \param $num - which mac address to check - 0 or 1
+	/// \param $compid - (optional) a computer id to ignore
+	///
+	/// \return 1 if $mac/$num is already in the computer table, 0 if not
+	///
+	/// \brief checks for $mac being somewhere in the computer table except
+	/// for $compid
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function checkForMACaddress($mac, $num, $compid='') {
+		if($num == 0)
+			$field = 'eth0macaddress';
+		else
+			$field = 'eth1macaddress';
+		$query = "SELECT id FROM computer "
+		       . "WHERE $field = '$mac' AND "
+		       .       "deleted = 0";
+		if(! empty($compid))
+			$query .= " AND id != $compid";
+		$qh = doQuery($query);
+		if(mysql_num_rows($qh))
+			return 1;
+		return 0;
+	}
+	
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn checkForIPaddress($ipaddress, $type, $compid)
+	///
+	/// \param $ipaddress - a computer ip address
+	/// \param $type - 'public' or 'private' - which IP address to check
+	/// \param $compid - (optional) a computer id to ignore
+	///
+	/// \return 1 if $ipaddress is already in the computer table, 0 if not
+	///
+	/// \brief checks for $ipaddress being somewhere in the computer table except
+	/// for $compid
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function checkForIPaddress($ipaddress, $type, $compid='') {
+		if($type == 'public')
+			$field = 'IPaddress';
+		else
+			$field = 'privateIPaddress';
+		$query = "SELECT id FROM computer "
+		       . "WHERE $field = '$ipaddress'";
+		if(! empty($compid))
+			$query .= " AND id != $compid";
+		$qh = doQuery($query);
+		if(mysql_num_rows($qh))
+			return 1;
+		return 0;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn addResource($data)
+	///
+	/// \param $data - array of needed data for adding a new resource
+	///
+	/// \return id of new resource
+	///
+	/// \brief handles adding a new computer and other associated data to the
+	/// database
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function addResource($data) {
+		global $user;
+		$ownerid = getUserlistID($data['owner']);
+		$noimageid = getImageId('noimage');
+		$norevid = getProductionRevisionid($noimageid);
+		$keys = array('hostname',         'ownerid',
+		              'type',             'IPaddress',
+		              'privateIPaddress', 'eth0macaddress',
+		              'eth1macaddress',   'provisioningid',
+		              'stateid',          'platformid',
+		              'scheduleid',       'RAM',
+		              'procnumber',       'procspeed',
+		              'network',          'currentimageid',
+		              'imagerevisionid',  'location');
+		if($data['addmode'] == 'single') {
+			$eth0 = "'{$data['eth0macaddress']}'";
+			if($data['eth0macaddress'] == '')
+				$eth0 = 'NULL';
+			$eth1 = "'{$data['eth1macaddress']}'";
+			if($data['eth1macaddress'] == '')
+				$eth1 = 'NULL';
+			$values = array("'{$data['name']}'",             $ownerid,
+			                "'{$data['type']}'",          "'{$data['IPaddress']}'",
+			                "'{$data['privateIPaddress']}'", $eth0,
+			                   $eth1,                        $data['provisioningid'],
+			                   $data['stateid'],             $data['platformid'],
+			                   $data['scheduleid'],          $data['ram'],
+			                   $data['cores'],               $data['procspeed'],
+			                   $data['network'],             $noimageid,
+			                   $norevid,                  "'{$data['location']}'");
+	
+			$query = "INSERT INTO computer ("
+			       . implode(', ', $keys) . ") VALUES ("
+			       . implode(', ', $values) . ")";
+			doQuery($query);
+	
+			$rscid = dbLastInsertID();
+
+			# vmhost entry
+			if($data['stateid'] == '20') {
+				$query = "INSERT INTO vmhost "
+				       .        "(computerid, "
+				       .        "vmlimit, "
+				       .        "vmprofileid) "
+				       . "VALUES ($rscid, "
+				       .        "5, "
+				       .        "{$data['vmprofileid']})";
+				doQuery($query);
+			}
+		
+			// add entry in resource table
+			$query = "INSERT INTO resource "
+					 .        "(resourcetypeid, "
+					 .        "subid) "
+					 . "VALUES (12, "
+					 .         "$rscid)";
+			doQuery($query);
+
+			return $rscid;
+		}
+		else {
+			# add multiple computers
+			$alldis = array();
+			for($i = $data['startnum'], $cnt = 0; $i <= $data['endnum']; $i++, $cnt++) {
+				$hostname = str_replace('%', $i, $data["name"]);
+				$pubip = long2ip($data['startpubiplong'] + $cnt);
+				$privip = long2ip($data['startpriviplong'] + $cnt);
+				if(count($data['macs'])) {
+					$eth0 = "'" . $data['macs'][$cnt * 2] . "'";
+					$eth1 = "'" . $data['macs'][($cnt * 2) + 1] . "'";
+				}
+				else {
+					$eth0 = 'NULL';
+					$eth1 = 'NULL';
+				}
+				$values = array("'$hostname'",          $ownerid,
+				                "'{$data['type']}'",  "'$pubip'",
+				                 "'$privip'",           $eth0,
+				                   $eth1,               $data['provisioningid'],
+				                   $data['stateid'],    $data['platformid'],
+				                   $data['scheduleid'], $data['ram'],
+				                   $data['cores'],      $data['procspeed'],
+				                   $data['network'],    $noimageid,
+				                   $norevid,         "'{$data['location']}'");
+		
+				$query = "INSERT INTO computer ("
+				       . implode(', ', $keys) . ") VALUES ("
+				       . implode(', ', $values) . ")";
+				doQuery($query);
+		
+				$rscid = dbLastInsertID();
+	
+				# vmhost entry
+				if($data['stateid'] == '20') {
+					$query = "INSERT INTO vmhost "
+					       .        "(computerid, "
+					       .        "vmlimit, "
+					       .        "vmprofileid) "
+					       . "VALUES ($rscid, "
+					       .        "5, "
+					       .        "{$data['vmprofileid']})";
+					doQuery($query);
+				}
+			
+				// add entry in resource table
+				$query = "INSERT INTO resource "
+						 .        "(resourcetypeid, "
+						 .        "subid) "
+						 . "VALUES (12, "
+						 .         "$rscid)";
+				doQuery($query);
+
+				$allids[] = $rscid;
+			}
+			return $allids;
+		}
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn AJcanceltovmhostinuse()
+	///
+	/// \brief cancels any reservations to place the computer in the vmhostinuse
+	/// state
+	///
+	////////////////////////////////////////////////////////////////////////////////
+	function AJcanceltovmhostinuse() {
+		global $mysql_link_vcl;
+		$compid = getContinuationVar('compid');
+		$type = 'none';
+		$query = "DELETE FROM request "
+		       . "WHERE start > NOW() AND "
+		       .       "stateid = 21 AND "
+		       .       "id IN (SELECT requestid "
+		       .              "FROM reservation "
+		       .              "WHERE computerid = $compid)";
+		doQuery($query);
+		if(mysql_affected_rows($mysql_link_vcl))
+			$type = 'future';
+		$query = "UPDATE request rq, "
+		       .         "reservation rs, "
+		       .         "state ls "
+		       . "SET rq.stateid = 1 "
+		       . "WHERE rs.requestid = rq.id AND "
+		       .       "rs.computerid = $compid AND "
+		       .       "rq.start <= NOW() AND "
+		       .       "rq.laststateid = ls.id AND "
+		       .       "ls.name = 'tovmhostinuse'";
+		doQuery($query);
+		if(mysql_affected_rows($mysql_link_vcl))
+			$type = 'current';
+		$query = "SELECT rq.start "
+		       . "FROM request rq, "
+		       .      "reservation rs, "
+		       .      "state ls, "
+		       .      "state cs "
+		       . "WHERE rs.requestid = rq.id AND "
+		       .       "rs.computerid = $compid AND "
+		       .       "rq.laststateid = ls.id AND "
+		       .       "rq.stateid = cs.id AND "
+		       .       "ls.name = 'tovmhostinuse' AND "
+		       .       "cs.name NOT IN ('failed', 'maintenance', 'complete', 'deleted') AND "
+		       .       "rq.end > NOW() "
+		       . "ORDER BY rq.start";
+		$qh = doQuery($query);
+		if(mysql_num_rows($qh))
+			$arr = array('status' => 'failed');
+		else {
+			if($type == 'now')
+				$msg = "The reservation currently being processed to place this "
+				     . "computer in the vmhostinuse state has been flagged for "
+				     . "deletion. As soon as the deletion can be processed, the "
+				     . "computer will be set to the available state.";
+			else
+				$msg = "The reservation scheduled to place this computer in the "
+				     . "vmhostinuse state has been deleted.";
+			$arr = array('status' => 'success', 'msg' => $msg);
+		}
+		sendJSON($arr);
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn scheduleTovmhostinuse($compid, $imageid, $start, $vmprofileid,
+	///                           $oldvmprofileid)
+	///
+	/// \param $compid - id of a computer
+	/// \param $imageid - id of an image
+	/// \param $start - start time in unix timestamp format
+	/// \param $vmprofileid - id of vmprofile
+	/// \param $oldvmprofileid - id of possible previous vmprofile
+	///
+	/// \return 0 on failure, 1 on success
+	///
+	/// \brief schedules or updates a reservation to move a host to the
+	/// vmhostinuse state
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function scheduleTovmhostinuse($compid, $imageid, $start, $vmprofileid,
+	                               $oldvmprofileid) {
+		# create a reload reservation to load machine with image
+		#   corresponding to selected vm profile
+		$vclreloadid = getUserlistID('vclreload@Local');
+		$revid = getProductionRevisionid($imageid);
+		$end = $start + SECINYEAR; # don't want anyone making a future reservation for this machine
+		$startdt = unixToDatetime($start);
+		$enddt = unixToDatetime($end);
+		$failed = 0;
+
+		$mnid = findManagementNode($compid, $startdt, 'now');
+		if($mnid == 0)
+			return 0;
+
+		# check for existing tovmhostinuse reservation
+		$query = "SELECT rq.id, "
+		       .        "rq.start, "
+		       .        "rq.end, "
+		       .        "rs.imageid "
+		       . "FROM request rq, "
+		       .      "reservation rs "
+		       . "WHERE rs.requestid = rq.id AND "
+		       .       "rs.computerid = $compid AND "
+		       .       "rq.stateid = 21 AND "
+		       .       "rq.start > NOW() "
+		       . "ORDER BY rq.start "
+		       . "LIMIT 1";
+		$qh = doQuery($query);
+		if($row = mysql_fetch_assoc($qh)) {
+			if(! retryGetSemaphore($imageid, $revid, $mnid, $compid, $startdt, $enddt, $row['id']))
+				return 0;
+			# update existing reservation
+			$updates = array();
+			$startts = datetimeToUnix($row['start']);
+			if($start < $startts)
+				$updates[] = "rq.start = '$startdt'";
+			elseif($start > $startts)
+				$this->startchange = $startts;
+			if($row['imageid'] != $imageid)
+				$updates[] = "rs.imageid = $imageid";
+			if(count($updates)) {
+				$query = "UPDATE request rq, "
+				       .        "reservation rs "
+				       . "SET " . implode(',', $updates) 
+				       ." WHERE rs.requestid = rq.id AND "
+				       .       "rq.id = {$row['id']}";
+				doQuery($query);
+			}
+		}
+		else {
+			if(! retryGetSemaphore($imageid, $revid, $mnid, $compid, $startdt, $enddt))
+				return 0;
+			# add new reservation
+			if(! (simpleAddRequest($compid, $imageid, $revid, $startdt, $enddt, 21,
+			                       $vclreloadid)))
+				return 0;
+		}
+
+		cleanSemaphore();
+
+		$this->updateVmhostProfile($compid, $vmprofileid, $oldvmprofileid);
+
+		return 1;
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn updateVmhostProfile($compid, $newprofileid, $oldprofileid)
+	///
+	/// \param $compid - id of computer
+	/// \param $newprofileid - id of new vmprofile
+	/// \param $oldprofileid - id of possible previous vmprofile
+	///
+	/// \brief updates a vmhost entry's vmprofileid or creates a new vmhost entry
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function updateVmhostProfile($compid, $newprofileid, $oldprofileid) {
+		if(is_numeric($oldprofileid)) {
+			if($oldprofileid != $newprofileid) {
+				# update existing entry
+				$query = "UPDATE vmhost "
+				       . "SET vmprofileid = $newprofileid "
+				       . "WHERE computerid = $compid AND "
+				       .       "vmprofileid = $oldprofileid";
+				doQuery($query);
+			}
+		}
+		else {
+			# create vmhost entry
+			$query = "INSERT INTO vmhost "
+			       .        "(computerid, "
+			       .        "vmlimit, "
+			       .        "vmprofileid) "
+			       . "VALUES ($compid, "
+			       .        "5, "
+			       .        "$newprofileid)";
+			doQuery($query);
+		}
+	}
+
+	/////////////////////////////////////////////////////////////////////////////
+	///
+	/// \fn AJsubmitComputerStateLater()
+	///
+	/// \brief schedules a computer to be converted to another state at a future
+	/// time
+	///
+	/////////////////////////////////////////////////////////////////////////////
+	function AJsubmitComputerStateLater() {
+		$compid = getContinuationVar('compid');
+		$maintenanceonly = getContinuationVar('maintenanceonly', 0);
+		$start = getContinuationVar('reloadstart');
+		$end = $start + SECINYEAR;
+		$startdt = unixToDatetime($start);
+		$enddt = unixToDatetime($end);
+		$vmprofileid = getContinuationVar('vmprofileid', 0);
+		$oldprofileid = getContinuationVar('oldprofileid', 0);
+		$newstateid = getContinuationVar('newstateid', 0);
+		$oldstateid = getContinuationVar('oldstateid', 0);
+		$imageid = getContinuationVar('imageid');
+		$revid = getProductionRevisionid($imageid);
+		$mode = processInputVar('mode', ARG_STRING);
+		$msg = '';
+		$refreshcount = 0;
+
+		if($oldstateid == 10 && $newstateid == 20 &&
+		   ! is_null($mode) && $mode != 'direct' && $mode != 'reload') {
+			$errmsg = "Invalid information submitted";
+			$ret = array('status' => 'error',
+			             'errormsg' => $errmsg);
+			sendJSON($ret);
+			return;
+		}
+
+		$delayed = 0;
+
+		# maintenance directly back to vmhostinuse
+		if($mode == 'direct') {
+			$vmids = getContinuationVar('vmids');
+			if(count($vmids)) {
+				$allids = implode(',', $vmids);
+				$query = "UPDATE computer "
+				       . "SET stateid = 2, "
+				       .     "notes = '' "
+				       . "WHERE id in ($allids)";
+				doQuery($query);
+			}
+			$query = "UPDATE computer "
+			       . "SET stateid = 20, "
+			       .     "notes = '' "
+			       . "WHERE id = $compid";
+			doQuery($query);
+			$msg .= "The computer has been moved back to the vmhostinuse state and ";
+			$msg .= "the appropriate VMs have been moved to the available state.";
+			$title = "Change to vmhostinuse";
+			$refreshcount = 1;
+		}
+		# maintenance back to vmhostinuse with a reload
+		elseif($mode == 'reload') {
+			$vmids = getContinuationVar('vmids');
+			if(count($vmids))
+				$this->scheduleVMsToAvailable($vmids);
+			$start = getReloadStartTime();
+			$rc = $this->scheduleTovmhostinuse($compid, $imageid, $start,
+			                                   $vmprofileid, $oldprofileid);
+
+			if($rc == 0) {
+				$errmsg .= "A problem was encountered while attempting to reload the ";
+				$errmsg .= "computer with the selected VM Host Profile. Please try ";
+				$errmsg .= "again at a later time.\n";
+				$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $errmsg);
+				$ret = array('status' => 'error',
+				             'errormsg' => $errmsg);
+				sendJSON($ret);
+				return;
+			}
+			$msg .= "The computer has been scheduled to go back to the vmhostinuse ";
+			$msg .= "state and the appropriate VMs have been scheduled to go back ";
+			$msg .= "to the available state at %s.";
+			$title = "Change to vmhostinuse";
+		}
+		# anything else to vmhostinuse
+		elseif($oldstateid != 20 && $newstateid == 20) {
+			moveReservationsOffComputer($compid);
+			cleanSemaphore();
+	
+			$mnid = findManagementNode($compid, unixToDatetime($start), 'future');
+			$tmp = getCompFinalReservationTime($compid, 21);
+			$checkstart = getExistingChangeStateStartTime($compid, 21);
+			if(! $checkstart && $checkstart != $start && $tmp > $start) {
+				$delayed = 1;
+				$start = $tmp;
+				$end = $start + SECINYEAR;
+				$startdt = unixToDatetime($start);
+				$enddt = unixToDatetime($end);
+			}
+			$vclreloadid = getUserlistID('vclreload@Local');
+			if($maintenanceonly) {

[... 2117 lines stripped ...]