r2906 - maintenance->trunk sync of changesets 2886~2894
[racktables] / inc / interface.php
index ba6d6a0..36a593c 100644 (file)
@@ -141,9 +141,6 @@ $image['CREATE']['height'] = 32;
 $image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
 $image['DENIED']['width'] = 32;
 $image['DENIED']['height'] = 32;
-$image['apply']['path'] = 'pix/tango-emblem-system.png';
-$image['apply']['width'] = 16;
-$image['apply']['height'] = 16;
 $image['node-collapsed']['path'] = 'pix/node-collapsed.png';
 $image['node-collapsed']['width'] = 16;
 $image['node-collapsed']['height'] = 16;
@@ -192,6 +189,12 @@ $image['NET']['height'] = 32;
 $image['USER']['path'] = 'pix/crystal-edit-user-32x32.png';
 $image['USER']['width'] = 32;
 $image['USER']['height'] = 32;
+$image['setfilter']['path'] = 'pix/pgadmin3-viewfiltereddata.png';
+$image['setfilter']['width'] = 32;
+$image['setfilter']['height'] = 32;
+$image['resetfilter']['path'] = 'pix/pgadmin3-viewdata.png';
+$image['resetfilter']['width'] = 32;
+$image['resetfilter']['height'] = 32;
 
 // This may be populated later onsite, report rendering function will use it.
 // See the $systemreport for structure.
@@ -273,46 +276,46 @@ function renderIndex ()
 
 function renderRackspace ()
 {
-       $tagfilter = getTagFilter();
-       $tagfilter_str = getTagFilterStr ($tagfilter);
-       showMessageOrError();
        echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
-       renderTagFilterPortlet ($tagfilter, 'rack');
+       $cellfilter = getCellFilter();
+       renderCellFilterPortlet ($cellfilter, 'rack');
        echo '</td><td class=pcright>';
        echo '<table border=0 cellpadding=10 cellpadding=1>';
        // generate thumb gallery
-       $rackrowList = getRackspace ($tagfilter);
        global $nextorder;
        $rackwidth = getRackImageWidth();
        // Zero value effectively disables the limit.
        $maxPerRow = getConfigVar ('RACKS_PER_ROW');
        $order = 'odd';
-       foreach ($rackrowList as $rackrow)
+       foreach (getRackRows() as $row_id => $row_name)
        {
-               $rackList = getRacksForRow ($rackrow['row_id'], $tagfilter);
+               $rackList = filterCellList (listCells ('rack', $row_id), $cellfilter['expression']);
+               if (!count ($rackList) and count ($cellfilter['expression']))
+                       continue;
                $rackListIdx = 0;
-               foreach ($rackList as $rack)
-               {
-                       if ($rackListIdx % $maxPerRow == 0)
+               echo "<tr class=row_${order}><th class=tdleft>";
+               echo "<a href='".makeHref(array('page'=>'row', 'row_id'=>$row_id))."${cellfilter['urlextra']}'>";
+               echo "${row_name}</a></th><td><table border=0 cellspacing=5><tr>";
+               if (!count ($rackList))
+                       echo "<td>(empty row)</td>";
+               else
+                       foreach ($rackList as $rack)
                        {
-                               if ($rackListIdx > 0)
+                               if ($rackListIdx > 0 and $maxPerRow > 0 and $rackListIdx % $maxPerRow == 0)
+                               {
                                        echo '</tr></table></tr>';
-                               echo "<tr class=row_${order}><th class=tdleft>";
-                               echo "<a href='".makeHref(array('page'=>'row', 'row_id'=>$rackrow['row_id']))."${tagfilter_str}'>";
-                               echo "${rackrow['row_name']}</a>";
-                               if ($rackListIdx > 0)
-                                       echo ' (continued)';
-                               echo "</th><td><table border=0 cellspacing=5><tr>";
-                               $order = $nextorder[$order];
+                                       echo "<tr class=row_${order}><th class=tdleft>${row_name} (continued)";
+                                       echo "</th><td><table border=0 cellspacing=5><tr>";
+                               }
+                               echo "<td align=center><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
+                               echo "<img border=0 width=${rackwidth} height=";
+                               echo getRackImageHeight ($rack['height']);
+                               echo " title='${rack['height']} units'";
+                               echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
+                               echo "<br>${rack['name']}</a></td>";
+                               $rackListIdx++;
                        }
-                       echo "<td align=center><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
-                       echo "<img border=0 width=${rackwidth} height=";
-                       echo getRackImageHeight ($rack['height']);
-                       echo " title='${rack['height']} units'";
-                       echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
-                       echo "<br>${rack['name']}</a></td>";
-                       $rackListIdx++;
-               }
+               $order = $nextorder[$order];
                echo "</tr></table></tr>\n";
        }
        echo "</table>\n";
@@ -330,7 +333,6 @@ function renderRackspaceRowEditor ()
                printImageHREF ('create', 'Add new row', TRUE, 101);
                echo "</td></tr></form>";
        }
-       showMessageOrError();
        startPortlet ('Rows');
        echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
        echo "<tr><th>&nbsp;</th><th>Name</th><th>&nbsp;</th></tr>\n";
@@ -339,8 +341,8 @@ function renderRackspaceRowEditor ()
        foreach (getRackRows() as $row_id => $row_name)
        {
                echo "<tr><td>";
-               if (count (getRacksForRow ($row_id)))
-                       printImageHREF ('nodestroy', $rackrow['count'] . ' racks');
+               if ($rc = count (listCells ('rack', $row_id)))
+                       printImageHREF ('nodestroy', "${rc} rack(s) here");
                else
                {
                        echo "<a href=\"".makeHrefProcess(array('op'=>'delete', 'row_id'=>$row_id))."\">";
@@ -358,20 +360,15 @@ function renderRackspaceRowEditor ()
        finishPortlet();
 }
 
-function renderRow ($row_id = 0)
+function renderRow ($row_id)
 {
-       if ($row_id == 0)
-       {
-               showError ('Invalid row_id', __FUNCTION__);
-               return;
-       }
        if (($rowInfo = getRackRowInfo ($row_id)) == NULL)
        {
                showError ('getRackRowInfo() failed', __FUNCTION__);
                return;
        }
-       $tagfilter = getTagFilter();
-       $rackList = getRacksForRow ($row_id, $tagfilter);
+       $cellfilter = getCellFilter();
+       $rackList = filterCellList (listCells ('rack', $row_id), $cellfilter['expression']);
        // Main layout starts.
        echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
 
@@ -386,8 +383,9 @@ function renderRow ($row_id = 0)
        echo "</td></tr>\n";
        echo "</table><br>\n";
        finishPortlet();
+       renderCellFilterPortlet ($cellfilter, 'rack', 'row_id', $row_id);
 
-       echo "</td><td class=pcright rowspan=2>";
+       echo "</td><td class=pcright>";
 
        global $nextorder;
        $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
@@ -415,10 +413,6 @@ function renderRow ($row_id = 0)
        }
        echo "</tr></table>\n";
        finishPortlet();
-       echo "</td></tr>";
-
-       echo "<tr><td class=pcleft>";
-       renderTagFilterPortlet ($tagfilter, 'rack', 'row_id', $row_id);
        echo "</td></tr></table>";
 }
 
@@ -429,7 +423,7 @@ function showError ($info = '', $location = 'N/A')
        elseif ($location != 'N/A')
                $location = $location . '()';
        echo "<div class=msg_error>An error has occured in [${location}]. ";
-       if (empty ($info))
+       if (!strlen ($info))
                echo 'No additional information is available.';
        else
                echo "Additional information:<br><p>\n<pre>\n${info}\n</pre></p>";
@@ -455,7 +449,7 @@ function assertUIntArg ($argname, $caller = 'N/A', $allow_zero = FALSE)
                showError ("Parameter '${argname}' is less than zero (calling function is [${caller}]).", __FUNCTION__);
                die();
        }
-       if (!$allow_zero and $_REQUEST[$argname] == 0)
+       if (!$allow_zero and $_REQUEST[$argname] === 0)
        {
                showError ("Parameter '${argname}' is equal to zero (calling function is [${caller}]).", __FUNCTION__);
                die();
@@ -476,7 +470,7 @@ function assertStringArg ($argname, $caller = 'N/A', $ok_if_empty = FALSE)
                showError ("Parameter '${argname}' is not a string (calling function is [${caller}]).", __FUNCTION__);
                die();
        }
-       if (!$ok_if_empty and empty ($_REQUEST[$argname]))
+       if (!$ok_if_empty and !strlen ($_REQUEST[$argname]))
        {
                showError ("Parameter '${argname}' is an empty string (calling function is [${caller}]).", __FUNCTION__);
                die();
@@ -495,7 +489,7 @@ function assertBoolArg ($argname, $caller = 'N/A', $ok_if_empty = FALSE)
                showError ("Parameter '${argname}' is not a string (calling function is [${caller}]).", __FUNCTION__);
                die();
        }
-       if (!$ok_if_empty and empty ($_REQUEST[$argname]))
+       if (!$ok_if_empty and !strlen ($_REQUEST[$argname]))
        {
                showError ("Parameter '${argname}' is an empty string (calling function is [${caller}]).", __FUNCTION__);
                die();
@@ -505,7 +499,7 @@ function assertBoolArg ($argname, $caller = 'N/A', $ok_if_empty = FALSE)
 function assertIPv4Arg ($argname, $caller = 'N/A', $ok_if_empty = FALSE)
 {
        assertStringArg ($argname, $caller, $ok_if_empty);
-       if (!empty ($_REQUEST[$argname]) and long2ip (ip2long ($_REQUEST[$argname])) !== $_REQUEST[$argname])
+       if (strlen ($_REQUEST[$argname]) and long2ip (ip2long ($_REQUEST[$argname])) !== $_REQUEST[$argname])
        {
                showError ("IPv4 address validation failed for value '" . $_REQUEST[$argname] . "' (calling function is [${caller}]).", __FUNCTION__);
                die();
@@ -513,18 +507,10 @@ function assertIPv4Arg ($argname, $caller = 'N/A', $ok_if_empty = FALSE)
 }
 
 // This function renders rack as HTML table.
-function renderRack ($rack_id = 0, $hl_obj_id = 0)
+function renderRack ($rack_id, $hl_obj_id = 0)
 {
-       if ($rack_id == 0)
-       {
-               showError ('Invalid rack_id', __FUNCTION__);
-               return;
-       }
-       if (($rackData = getRackData ($rack_id)) == NULL)
-       {
-               showError ('getRackData() failed', __FUNCTION__);
-               return;
-       }
+       $rackData = spotEntity ('rack', $rack_id);
+       amplifyCell ($rackData);
        markAllSpans ($rackData);
        if ($hl_obj_id > 0)
                highlightObject ($rackData, $hl_obj_id);
@@ -570,13 +556,13 @@ function renderRack ($rack_id = 0, $hl_obj_id = 0)
                        switch ($state)
                        {
                                case 'T':
-                                       $objectData = getObjectInfo ($rackData[$i][$locidx]['object_id']);
-                                       if (!empty ($objectData['asset_no']))
+                                       $objectData = spotEntity ('object', $rackData[$i][$locidx]['object_id']);
+                                       if (strlen ($objectData['asset_no']))
                                                $prefix = "<div title='${objectData['asset_no']}";
                                        else
                                                $prefix = "<div title='no asset tag";
                                        // Don't tell about label, if it matches common name.
-                                       if ($objectData['name'] != $objectData['label'] and !empty ($objectData['label']))
+                                       if ($objectData['name'] != $objectData['label'] and strlen ($objectData['label']))
                                                $suffix = ", visible label is \"${objectData['label']}\"'>";
                                        else
                                                $suffix = "'>";
@@ -605,8 +591,6 @@ function renderRack ($rack_id = 0, $hl_obj_id = 0)
 
 function renderNewRackForm ($row_id)
 {
-       showMessageOrError();
-
        startPortlet ('Add one');
        printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
        echo '<table border=0 align=center>';
@@ -615,7 +599,7 @@ function renderNewRackForm ($row_id)
                $defh = '';
        echo "<tr><th class=tdright>Rack name (*):</th><td class=tdleft><input type=text name=rack_name tabindex=1></td>";
        echo "<td rowspan=4>Assign tags:<br>";
-       renderNewEntityTags();
+       renderNewEntityTags ('rack');
        echo "</td></tr>\n";
        echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height1 tabindex=2 value='${defh}'></td></tr>\n";
        echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment tabindex=3></td></tr>\n";
@@ -632,7 +616,7 @@ function renderNewRackForm ($row_id)
                $defh = '';
        echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height2 value='${defh}'></td>";
        echo "<td rowspan=3 valign=top>Assign tags:<br>";
-       renderNewEntityTags();
+       renderNewEntityTags ('rack');
        echo "</td></tr>\n";
        echo "<tr><th class=tdright>Rack names (*):</th><td class=tdleft><textarea name=rack_names cols=40 rows=25></textarea></td></tr>\n";
        echo "<tr><td class=submit colspan=2>";
@@ -643,13 +627,11 @@ function renderNewRackForm ($row_id)
 
 function renderEditObjectForm ($object_id)
 {
-       showMessageOrError();
-
        global $pageno;
-       $object = getObjectInfo ($object_id);
+       $object = spotEntity ('object', $object_id);
        if ($object == NULL)
        {
-               showError ('getObjectInfo() failed', __FUNCTION__);
+               showError ('Error retrieving data', __FUNCTION__);
                return;
        }
        startPortlet ();
@@ -668,15 +650,15 @@ function renderEditObjectForm ($object_id)
        echo "<tr><td>&nbsp;</td><th class=tdright>Barcode:</th><td class=tdleft><input type=text name=object_barcode value='${object['barcode']}'></td></tr>\n";
        // optional attributes
        $values = getAttrValues ($object_id);
+       echo '<input type=hidden name=num_attrs value=' . count($values) . ">\n";
        if (count($values) > 0)
        {
-               echo '<input type=hidden name=num_attrs value=' . count($values) . ">\n";
                $i = 0;
                foreach ($values as $record)
                {
                        echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
                        echo '<tr><td>';
-                       if (!empty ($record['value']))
+                       if (strlen ($record['value']))
                        {
                                echo "<a href='".makeHrefProcess(array('op'=>'clearSticker', 'object_id'=>$object_id, 'attr_id'=>$record['id']))."'>";
                                printImageHREF ('clear', 'Clear value');
@@ -728,14 +710,9 @@ function renderEditObjectForm ($object_id)
 // This is a clone of renderEditObjectForm().
 function renderEditRackForm ($rack_id)
 {
-       showMessageOrError();
        global $pageno;
-       $rack = getRackData ($rack_id);
-       if ($rack == NULL)
-       {
-               showError ('getRackData() failed', __FUNCTION__);
-               return;
-       }
+       $rack = spotEntity ('rack', $rack_id);
+       amplifyCell ($rack);
 
        startPortlet ('Rack attributes');
        printOpFormIntro ('updateRack');
@@ -806,10 +783,10 @@ function renderRackInfoPortlet ($rackData)
        renderProgressBar (getRSUforRack ($rackData));
        echo "</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Objects:</th><td class=tdleft>";
-       echo count (stuffInRackspace ($rackData));
+       echo count ($rackData['mountedObjects']);
        echo "</td></tr>\n";
-       printTagTRs (makeHref(array('page'=>'rackspace', 'tab'=>'default'))."&");
-       if (!empty ($rackData['comment']))
+       printTagTRs ($rackData, makeHref(array('page'=>'rackspace', 'tab'=>'default'))."&");
+       if (strlen ($rackData['comment']))
                echo "<tr><th width='50%' class=tdright>Comment:</th><td class=tdleft>${rackData['comment']}</td></tr>\n";
        echo '</table>';
        finishPortlet();
@@ -817,19 +794,10 @@ function renderRackInfoPortlet ($rackData)
 
 // This is a universal editor of rack design/waste.
 // FIXME: switch to using printOpFormIntro()
-function renderGridForm ($rack_id = 0, $filter, $header, $submit, $state1, $state2)
+function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2)
 {
-       if ($rack_id == 0)
-       {
-               showError ('Invalid rack_id', __FUNCTION__);
-               return;
-       }
-       if (($rackData = getRackData ($rack_id)) == NULL)
-       {
-               showError ('getRackData() failed', __FUNCTION__);
-               return;
-       }
-       showMessageOrError();
+       $rackData = spotEntity ('rack', $rack_id);
+       amplifyCell ($rackData);
        $filter ($rackData);
        markupObjectProblems ($rackData);
 
@@ -866,7 +834,7 @@ function renderRackDesign ($rack_id)
        renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
 }
 
-function renderRackProblems ($rack_id = 0)
+function renderRackProblems ($rack_id)
 {
        renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
 }
@@ -881,18 +849,15 @@ function finishPortlet ()
        echo "</div>\n";
 }
 
-function renderRackObject ($object_id = 0)
+function renderRackObject ($object_id)
 {
        global $nextorder, $aac;
-       if ($object_id <= 0)
-       {
-               showError ('Invalid object_id', __FUNCTION__);
-               return;
-       }
-       $info = getObjectInfo ($object_id);
+       $info = spotEntity ('object', $object_id);
+       // FIXME: employ amplifyCell() instead of calling loader functions directly
+       amplifyCell ($info);
        if ($info == NULL)
        {
-               showError ('getObjectInfo() failed', __FUNCTION__);
+               showError ('Error loading data', __FUNCTION__);
                return;
        }
        // Main layout starts.
@@ -902,9 +867,10 @@ function renderRackObject ($object_id = 0)
        echo "<tr><td class=pcleft>";
        startPortlet ('summary');
        echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
-       if (!empty ($info['name']))
+       if (strlen ($info['name']))
                echo "<tr><th width='50%' class=tdright>Common name:</th><td class=tdleft>${info['name']}</td></tr>\n";
-       elseif (considerConfiguredConstraint ('object', $object_id, 'NAMEWARN_LISTSRC'))
+       // FIXME: don't call spotEntity() each time, do it once in the beginning.
+       elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
                echo "<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Object type:</th><td class=tdleft><a href='";
        echo makeHref (array (
@@ -913,21 +879,23 @@ function renderRackObject ($object_id = 0)
                'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
        ));
        echo "'>${info['objtype_name']}</a></td></tr>\n";
-       if (!empty ($info['asset_no']))
+       if (strlen ($info['asset_no']))
                echo "<tr><th width='50%' class=tdright>Asset tag:</th><td class=tdleft>${info['asset_no']}</td></tr>\n";
-       elseif (considerConfiguredConstraint ('object', $object_id, 'ASSETWARN_LISTSRC'))
+       // FIXME: ditto
+       elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
                echo "<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>\n";
-       if (!empty ($info['label']))
+       if (strlen ($info['label']))
                echo "<tr><th width='50%' class=tdright>Visible label:</th><td class=tdleft>${info['label']}</td></tr>\n";
-       if (!empty ($info['barcode']))
+       if (strlen ($info['barcode']))
                echo "<tr><th width='50%' class=tdright>Barcode:</th><td class=tdleft>${info['barcode']}</td></tr>\n";
        if ($info['has_problems'] == 'yes')
                echo "<tr><td colspan=2 class=msg_error>Has problems</td></tr>\n";
        foreach (getAttrValues ($object_id, TRUE) as $record)
-               if (!empty ($record['value']))
+               if (strlen ($record['value']))
                        echo "<tr><th width='50%' class=sticker>${record['name']}:</th><td class=sticker>${record['a_value']}</td></tr>\n";
        printTagTRs
        (
+               $info,
                makeHref
                (
                        array
@@ -935,14 +903,14 @@ function renderRackObject ($object_id = 0)
                                'page'=>'depot',
                                'tab'=>'default',
                                'andor' => 'and',
-                               'cfe'=>'{$typeid_' . $info['objtype_id'] . '}'
+                               'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
                        )
                )."&"
        );
        echo "</table><br>\n";
        finishPortlet();
 
-       if (!empty ($info['comment']))
+       if (strlen ($info['comment']))
        {
                startPortlet ('Comment');
                echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
@@ -951,7 +919,7 @@ function renderRackObject ($object_id = 0)
 
        renderFilesPortlet ('object', $object_id);
 
-       $ports = getObjectPortsAndLinks ($object_id);
+       $ports = $info['ports'];
        if (count ($ports))
        {
                startPortlet ('ports and links');
@@ -979,7 +947,7 @@ function renderRackObject ($object_id = 0)
                                        echo "<td><a href='".makeHref(array('page'=>'object', 'object_id'=>$port['remote_object_id'], 'hl_port_id'=>$port['remote_id']))."'>${port['remote_object_name']}</a></td>";
                                        echo "<td>${port['remote_name']}</td>";
                                }
-                               elseif (!empty ($port['reservation_comment']))
+                               elseif (strlen ($port['reservation_comment']))
                                {
                                        echo "<td><b>Reserved;</b></td>";
                                        echo "<td>${port['reservation_comment']}</td>";
@@ -993,7 +961,7 @@ function renderRackObject ($object_id = 0)
                finishPortlet();
        }
 
-       $alloclist = getObjectIPv4Allocations ($object_id);
+       $alloclist = $info['ipv4'];
        if (count ($alloclist))
        {
                startPortlet ('IPv4 addresses');
@@ -1016,7 +984,7 @@ function renderRackObject ($object_id = 0)
                        $netid = getIPv4AddressNetworkId ($dottedquad);
                        if (NULL !== $netid)
                        {
-                               $netinfo = getIPv4NetworkInfo ($netid);
+                               $netinfo = spotEntity ('ipv4net', $netid);
                                loadIPv4AddrList ($netinfo);
                        }
                        echo "<tr class='${class}' valign=top><td class=tdleft>${alloc['osif']}</td><td class='${secondclass}'>";
@@ -1027,7 +995,7 @@ function renderRackObject ($object_id = 0)
                        if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
                                echo '<small>/' . (NULL === $netid ? '??' : $netinfo['mask']) . '</small>';
                        echo '&nbsp;' . $aac[$alloc['type']];
-                       if (!empty ($alloc['addrinfo']['name']))
+                       if (strlen ($alloc['addrinfo']['name']))
                                echo ' (' . niftyString ($alloc['addrinfo']['name']) . ')';
                        echo '</td>';
                        if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
@@ -1037,7 +1005,7 @@ function renderRackObject ($object_id = 0)
                                else
                                {
                                        echo "<td class='${secondclass}'>";
-                                       renderIPv4NetCell ($netinfo);
+                                       renderCell ($netinfo);
                                        echo "</td>";
                                        // filter out self-allocation
                                        $other_routers = array();
@@ -1063,7 +1031,7 @@ function renderRackObject ($object_id = 0)
                                if ($allocpeer['object_id'] == $object_id)
                                        continue;
                                echo $prefix . "<a href='".makeHref(array('page'=>'object', 'object_id'=>$allocpeer['object_id']))."'>";
-                               if (!empty ($allocpeer['osif']))
+                               if (isset ($allocpeer['osif']) and strlen ($allocpeer['osif']))
                                        echo $allocpeer['osif'] . '@';
                                echo $allocpeer['object_name'] . '</a>';
                                $prefix = '; ';
@@ -1074,7 +1042,7 @@ function renderRackObject ($object_id = 0)
                finishPortlet();
        }
 
-       $forwards = getNATv4ForObject ($object_id);
+       $forwards = $info['nat4'];
        if (count($forwards['in']) or count($forwards['out']))
        {
                startPortlet('NATv4');
@@ -1104,7 +1072,7 @@ function renderRackObject ($object_id = 0)
                                if (count ($address['allocs']))
                                        foreach($address['allocs'] as $bond)
                                                echo "<a href='".makeHref(array('page'=>'object', 'tab'=>'default', 'object_id'=>$bond['object_id']))."'>${bond['object_name']}(${bond['name']})</a> ";
-                               elseif (!empty ($pf['remote_addr_name']))
+                               elseif (strlen ($pf['remote_addr_name']))
                                        echo '(' . $pf['remote_addr_name'] . ')';
                                echo "</td><td class='description'>${pf['description']}</td></tr>";
                        }
@@ -1128,7 +1096,7 @@ function renderRackObject ($object_id = 0)
                finishPortlet();
        }
 
-       $pools = getRSPoolsForObject ($object_id);
+       $pools = $info['ipv4rspools'];
        if (count ($pools))
        {
                $order = 'odd';
@@ -1138,9 +1106,9 @@ function renderRackObject ($object_id = 0)
                foreach ($pools as $vs_id => $info)
                {
                        echo "<tr valign=top class=row_${order}><td class=tdleft>";
-                       renderVSCell ($vs_id);
+                       renderCell (spotEntity ('ipv4vs', $vs_id));
                        echo "</td><td class=tdleft>";
-                       renderRSPoolCell ($info['pool_id'], $info['pool_name']);
+                       renderCell (spotEntity ('ipv4rspool', $info['pool_id']));
                        echo '</td><td class=tdleft>' . $info['rscount'] . '</td>';
                        echo "<td class=slbconf>${info['vsconfig']}</td>";
                        echo "<td class=slbconf>${info['rsconfig']}</td>";
@@ -1188,17 +1156,8 @@ function renderRackMultiSelect ($sname, $racks, $selected)
        echo "</select>\n";
 }
 
-function showMessageOrError ()
-{
-       if (isset ($_SESSION['log']))
-       {
-               printLog ($_SESSION['log']);
-               unset($_SESSION['log']);
-       }
-}
-
 // This function renders a form for port edition.
-function renderPortsForObject ($object_id = 0)
+function renderPortsForObject ($object_id)
 {
        function printNewItemTR ()
        {
@@ -1213,12 +1172,6 @@ function renderPortsForObject ($object_id = 0)
                printImageHREF ('add', 'add a port', TRUE, 104);
                echo "</td></tr></form>";
        }
-       if ($object_id <= 0)
-       {
-               showError ('Invalid object_id', __FUNCTION__);
-               return;
-       }
-       showMessageOrError();
        startPortlet ('Ports and interfaces');
        $ports = getObjectPortsAndLinks ($object_id);
        usort($ports, 'sortByName');
@@ -1263,7 +1216,7 @@ function renderPortsForObject ($object_id = 0)
                        printImageHREF ('cut', 'Unlink this port');
                        echo "</a></td>";
                }
-               elseif (!empty ($port['reservation_comment']))
+               elseif (strlen ($port['reservation_comment']))
                {
                        echo "<td><b>Reserved;</b></td>";
                        echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
@@ -1310,7 +1263,7 @@ function renderPortsForObject ($object_id = 0)
        finishPortlet();
 }
 
-function renderIPv4ForObject ($object_id = 0)
+function renderIPv4ForObject ($object_id)
 {
        function printNewItemTR ()
        {
@@ -1327,15 +1280,10 @@ function renderIPv4ForObject ($object_id = 0)
                printImageHREF ('add', 'allocate', TRUE, 103);
                echo "</td></tr></form>";
        }
+       $focus = spotEntity ('object', $object_id);
+       amplifyCell ($focus);
        global $aat;
-       if ($object_id <= 0)
-       {
-               showError ('Invalid object_id', __FUNCTION__);
-               return;
-       }
-       showMessageOrError();
        startPortlet ('Allocations');
-       $alloclist = getObjectIPv4Allocations ($object_id);
        echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
        echo '<tr><th>&nbsp;</th><th>OS interface</th><th>IP address</th>';
        if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
@@ -1344,13 +1292,13 @@ function renderIPv4ForObject ($object_id = 0)
 
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
                printNewItemTR();
-       foreach ($alloclist as $dottedquad => $alloc)
+       foreach ($focus['ipv4'] as $dottedquad => $alloc)
        {
                $class = $alloc['addrinfo']['class'];
                $netid = getIPv4AddressNetworkId ($dottedquad);
                if (NULL !== $netid)
                {
-                       $netinfo = getIPv4NetworkInfo ($netid);
+                       $netinfo = spotEntity ('ipv4net', $netid);
                        loadIPv4AddrList ($netinfo);
                }
                printOpFormIntro ('updIPv4Allocation', array ('ip' => $dottedquad));
@@ -1364,7 +1312,7 @@ function renderIPv4ForObject ($object_id = 0)
                        echo $dottedquad;
                if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
                        echo '<small>/' . (NULL === $netid ? '??' : $netinfo['mask']) . '</small>';
-               if (!empty ($alloc['addrinfo']['name']))
+               if (strlen ($alloc['addrinfo']['name']))
                        echo ' (' . niftyString ($alloc['addrinfo']['name']) . ')';
                echo '</td>';
                // FIXME: this a copy-and-paste from renderRackObject()
@@ -1375,7 +1323,7 @@ function renderIPv4ForObject ($object_id = 0)
                        else
                        {
                                echo '<td>';
-                               renderIPv4NetCell ($netinfo);
+                               renderCell ($netinfo);
                                echo '</td>';
                                // filter out self-allocation
                                $other_routers = array();
@@ -1402,7 +1350,7 @@ function renderIPv4ForObject ($object_id = 0)
                        if ($allocpeer['object_id'] == $object_id)
                                continue;
                        echo $prefix . "<a href='".makeHref(array('page'=>'object', 'object_id'=>$allocpeer['object_id']))."'>";
-                       if (!empty ($allocpeer['osif']))
+                       if (isset ($allocpeer['osif']) and strlen ($allocpeer['osif']))
                                echo $allocpeer['osif'] . '@';
                        echo $allocpeer['object_name'] . '</a>';
                        $prefix = '; ';
@@ -1423,8 +1371,11 @@ function renderIPv4ForObject ($object_id = 0)
 // 1: the whole structure is a list of code-message pairs
 // 2 and later: there's a "v" field set, which indicates the version
 // 2: there's a "m" list set to hold message code and optional arguments
-function printLog ($log)
+function showMessageOrError ()
 {
+       if (!isset ($_SESSION['log']))
+               return;
+       $log = $_SESSION['log'];
        switch (TRUE)
        {
                case !isset ($log['v']):
@@ -1676,6 +1627,7 @@ function printLog ($log)
                        echo '<div class=msg_error>' . __FUNCTION__ . ': internal error</div>';
                        break;
        }
+       unset($_SESSION['log']);
 }
 
 /*
@@ -1687,31 +1639,19 @@ and either delete them before unmounting or refuse to unmount the object.
 */
 
 // We extensively use $_REQUEST in the function.
-// FIXME: move related code into ophandler
-function renderRackSpaceForObject ($object_id = 0)
+function renderRackSpaceForObject ($object_id)
 {
-       if ($object_id <= 0)
-       {
-               showError ('Invalid object_id', __FUNCTION__);
-               return;
-       }
-       $is_submit = isset ($_REQUEST['got_atoms']);
        $is_update = isset ($_REQUEST['rackmulti'][0]);
-       $info = getObjectInfo ($object_id);
+       $info = spotEntity ('object', $object_id);
        if ($info == NULL)
        {
-               showError ('getObjectInfo() failed', __FUNCTION__);
+               showError ('Error loading data', __FUNCTION__);
                return;
        }
        // Always process occupied racks plus racks chosen by user. First get racks with
        // already allocated rackspace...
-       $workingRacksData = getResidentRacksData ($object_id);
-       if ($workingRacksData === NULL)
-       {
-               print_r ($workingRacksData);
-               showError ('getResidentRacksData() failed', __FUNCTION__);
-               return;
-       }
+       if (NULL === ($workingRacksData = getResidentRacksData ($object_id)))
+               die; // some error already shown
 
        // ...and then add those chosen by user (if any).
        if (isset($_REQUEST['rackmulti']))
@@ -1719,12 +1659,12 @@ function renderRackSpaceForObject ($object_id = 0)
                {
                        if (!isset ($workingRacksData[$cand_id]))
                        {
-                               $rackData = getRackData ($cand_id);
-                               if ($rackData == NULL)
+                               if (NULL == ($rackData = spotEntity ('rack', $cand_id)))
                                {
-                                       showError ('getRackData() failed', __FUNCTION__);
+                                       showError ('Rack not found', __FUNCTION__);
                                        return NULL;
                                }
+                               amplifyCell ($rackData);
                                $workingRacksData[$cand_id] = $rackData;
                        }
                }
@@ -1741,7 +1681,6 @@ function renderRackSpaceForObject ($object_id = 0)
        unset ($rackData);
 
        // This is the time for rendering.
-       showMessageOrError();
 
        // Main layout starts.
        echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
@@ -1749,18 +1688,13 @@ function renderRackSpaceForObject ($object_id = 0)
        // Left portlet with rack list.
        echo "<td class=pcleft height='1%'>";
        startPortlet ('Racks');
-       $allRacksData = getRacksForRow();
+       $allRacksData = listCells ('rack');
        if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
        {
-               foreach (array_keys ($allRacksData) as $rack_id)
+               foreach ($allRacksData as $rack)
                {
-                       $rackData = getRackData ($rack_id);
-                       if ($rackData == NULL)
-                       {
-                               showError ('getRackData() failed', __FUNCTION__);
-                               return NULL;
-                       }
-                       $workingRacksData[$rack_id] = $rackData;
+                       amplifyCell ($rack);
+                       $workingRacksData[$rack_id] = $rack;
                }
                foreach ($workingRacksData as &$rackData)
                        applyObjectMountMask ($rackData, $object_id);
@@ -1794,7 +1728,7 @@ function renderRackSpaceForObject ($object_id = 0)
                markupAtomGrid ($rackData, 'T');
                // If we have a form processed, discard user input and show new database
                // contents.
-               if (!$is_submit and $is_update)
+               if ($is_update)
                        mergeGridFormToRack ($rackData);
                echo "<td valign=top>";
                echo "<center>\n<h2>${rackData['name']}</h2>\n";
@@ -1832,7 +1766,8 @@ function renderMolecule ($mdata, $object_id)
                $atom = $rua['atom'];
                if (!isset ($rackpack[$rack_id]))
                {
-                       $rackData = getRackData ($rack_id);
+                       $rackData = spotEntity ('rack', $rack_id);
+                       amplifyCell ($rackData);
                        for ($i = $rackData['height']; $i > 0; $i--)
                                for ($locidx = 0; $locidx < 3; $locidx++)
                                        $rackData[$i][$locidx]['state'] = 'F';
@@ -1877,7 +1812,6 @@ function renderEmptyPortsSelect ($port_id, $type_id)
 function renderDepot ()
 {
        global $pageno, $nextorder;
-       showMessageOrError();
        $cellfilter = getCellFilter();
        $objects = filterCellList (listCells ('object'), $cellfilter['expression']);
 
@@ -1899,10 +1833,9 @@ function renderDepot ()
                        $secondclass = 'tdleft port_highlight';
                else
                        $secondclass = 'tdleft';
-               $tags = loadEntityTags ('object', $obj['id']);
                echo "<tr class=row_${order} valign=top><td class='${secondclass}'><a href='".makeHref(array('page'=>'object', 'object_id'=>$obj['id']))."'><strong>${obj['dname']}</strong></a>";
-               if (count ($tags))
-                       echo '<br><small>' . serializeTags ($tags, makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
+               if (count ($obj['etags']))
+                       echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
                echo "</td><td class='${secondclass}'>${obj['label']}</td>";
                echo "<td class='${secondclass}'>${obj['asset_no']}</td>";
                echo "<td class='${secondclass}'>${obj['barcode']}</td>";
@@ -1928,25 +1861,25 @@ function renderHistory ($object_type, $object_id)
        switch ($object_type)
        {
                case 'row':
-                       $query = "select ctime, user_name, name, deleted, comment from RackRowHistory where id = ${object_id} order by ctime";
-                       $header = '<tr><th>change time</th><th>author</th><th>rack row name</th><th>is deleted?</th><th>rack row comment</th></tr>';
-                       $extra = 4;
+                       $query = "select ctime, user_name, name, comment from RackRowHistory where id = ${object_id} order by ctime";
+                       $header = '<tr><th>change time</th><th>author</th><th>rack row name</th><th>rack row comment</th></tr>';
+                       $extra = 3;
                        break;
                case 'rack':
                        $query =
-                               "select ctime, user_name, rh.name, rh.deleted, rr.name as name, rh.height, rh.comment " .
+                               "select ctime, user_name, rh.name, rr.name as name, rh.height, rh.comment " .
                                "from RackHistory as rh left join RackRow as rr on rh.row_id = rr.id " .
                                "where rh.id = ${object_id} order by ctime";
-                       $header = '<tr><th>change time</th><th>author</th><th>rack name</th><th>is deleted?</th><th>rack row name</th><th>rack height</th><th>rack comment</th></tr>';
-                       $extra = 6;
+                       $header = '<tr><th>change time</th><th>author</th><th>rack name</th><th>rack row name</th><th>rack height</th><th>rack comment</th></tr>';
+                       $extra = 5;
                        break;
                case 'object':
                        $query =
-                               "select ctime, user_name, RackObjectHistory.name as name, label, barcode, asset_no, deleted, has_problems, dict_value, comment " .
+                               "select ctime, user_name, RackObjectHistory.name as name, label, barcode, asset_no, has_problems, dict_value, comment " .
                                "from RackObjectHistory inner join Dictionary on objtype_id = dict_key join Chapter on Dictionary.chapter_id = Chapter.id " .
                                "where Chapter.name = 'RackObjectType' and RackObjectHistory.id=${object_id} order by ctime";
-                       $header = '<tr><th>change time</th><th>author</th><th>common name</th><th>visible label</th><th>barcode</th><th>asset no</th><th>is deleted?</th><th>has problems?</th><th>object type</th><th>comment</th></tr>';
-                       $extra = 9;
+                       $header = '<tr><th>change time</th><th>author</th><th>common name</th><th>visible label</th><th>barcode</th><th>asset no</th><th>has problems?</th><th>object type</th><th>comment</th></tr>';
+                       $extra = 8;
                        break;
                default:
                        showError ("Uknown object type '${object_type}'", __FUNCTION__);
@@ -2045,7 +1978,7 @@ function renderRackspaceHistory ()
        echo '</td></tr></table>';
 }
 
-function renderIPv4SpaceRecords ($tree, &$tagcache, $baseurl, $target = 0, $level = 1)
+function renderIPv4SpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
 {
        $self = __FUNCTION__;
        foreach ($tree as $item)
@@ -2083,10 +2016,10 @@ function renderIPv4SpaceRecords ($tree, &$tagcache, $baseurl, $target = 0, $leve
                                echo "<small>${total}</small>";
                        echo "</td>";
                        if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
-                               printRoutersTD (findRouters ($item['addrlist']), $tagcache);
+                               printRoutersTD (findRouters ($item['addrlist']));
                        echo "</tr>";
                        if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
-                               $self ($item['kids'], $tagcache, $baseurl, $target, $level + 1);
+                               $self ($item['kids'], $baseurl, $target, $level + 1);
                }
                else
                {
@@ -2122,12 +2055,15 @@ function renderIPv4Space ()
        startPortlet ("networks (${netcount})");
        echo '<h4>';
        if ($eid === 0)
-               echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL'))."'>expand all</a>)";
+               echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') .
+                       " (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
+                       $cellfilter['urlextra'] . "'>expand all</a>)";
        elseif ($eid === 'ALL')
-               echo "expanding all (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno))."'>auto-collapse</a>)";
+               echo "expanding all (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
+                       $cellfilter['urlextra'] . "'>auto-collapse</a>)";
        else
        {
-               $netinfo = getIPv4NetworkInfo ($eid);
+               $netinfo = spotEntity ('ipv4net', $eid);
                echo "expanding ${netinfo['ip']}/${netinfo['mask']} (<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno))."'>auto-collapse</a> / <a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL'))."'>expand&nbsp;all</a>)"; 
        }
        echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
@@ -2135,9 +2071,8 @@ function renderIPv4Space ()
        if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
                echo "<th>routed by</th>";
        echo "</tr>\n";
-       $tagcache = array();
-       $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . getTagFilterStr (getTagFilter());
-       renderIPv4SpaceRecords ($tree, $tagcache, $baseurl, $eid);
+       $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
+       renderIPv4SpaceRecords ($tree, $baseurl, $eid);
        echo "</table>\n";
        finishPortlet();
        echo '</td><td class=pcright>';
@@ -2166,7 +2101,7 @@ function renderIPv4SLB ()
                foreach (array_keys ($vipdata['lblist']) as $lb_object_id)
                        if (!in_array ($lb_object_id, $lblist))
                        {
-                               $oi = getObjectInfo ($lb_object_id);
+                               $oi = spotEntity ('object', $lb_object_id);
                                $lbdname[$lb_object_id] = $oi['dname'];
                                $lblist[] = $lb_object_id;
                        }
@@ -2188,7 +2123,7 @@ function renderIPv4SLB ()
                foreach ($summary as $vsid => $vsdata)
                {
                        echo "<tr class=row_${order}><td class=tdleft>";
-                       renderVSCell ($vsid);
+                       renderCell (spotEntity ('ipv4vs', $vsid));
                        echo "</td>";
                        foreach ($lblist as $lb_object_id)
                        {
@@ -2213,8 +2148,6 @@ function renderIPv4SLB ()
 
 function renderIPv4SpaceEditor ()
 {
-       showMessageOrError();
-
        // IPv4 validator
 ?>
        <script type="text/javascript">
@@ -2235,7 +2168,7 @@ function renderIPv4SpaceEditor ()
        echo "<input type=hidden name=op value=addIPv4Prefix>\n";
        // tags column
        echo '<tr><td rowspan=4><h3>assign tags</h3>';
-       renderNewEntityTags();
+       renderNewEntityTags ('ipv4net');
        echo '</td>';
        // inputs column
        echo "<th class=tdright>prefix</th><td class=tdleft><input type=text name='range' size=18 class='live-validate' tabindex=1></td>";
@@ -2266,7 +2199,7 @@ function renderIPv4SpaceEditor ()
                        }
                        else // only render clickable image for empty networks
                        {
-                               $netdata = getIPv4NetworkInfo ($netinfo['id']);
+                               $netdata = spotEntity ('ipv4net', $netinfo['id']);
                                loadIPv4AddrList ($netdata);
                                if (count ($netdata['addrlist']))
                                        printImageHREF ('nodestroy', 'There are ' . count ($netdata['addrlist']) . ' allocations inside');
@@ -2368,7 +2301,7 @@ function renderIPv4Network ($id)
        else
                $page=0;
 
-       $range = getIPv4NetworkInfo ($id);
+       $range = spotEntity ('ipv4net', $id);
        loadIPv4AddrList ($range);
        echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
        echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>${range['name']}</h2></td></tr>\n";
@@ -2390,25 +2323,24 @@ function renderIPv4Network ($id)
                $backtrace = array();
                while (NULL !== ($upperid = getIPv4AddressNetworkId ($range['ip'], $clen)))
                {
-                       $upperinfo = getIPv4NetworkInfo ($upperid);
+                       $upperinfo = spotEntity ('ipv4net', $upperid);
                        $clen = $upperinfo['mask'];
-                       $backtrace[] = $upperid;
+                       $backtrace[] = $upperinfo;
                }
                $arrows = count ($backtrace);
-               foreach (array_reverse ($backtrace) as $ancestorid)
+               foreach (array_reverse ($backtrace) as $ainfo)
                {
-                       $ainfo = getIPv4NetworkInfo ($ancestorid);
                        echo "<tr><th width='50%' class=tdright>";
                        for ($i = 0; $i < $arrows; $i++)
                                echo '&uarr;';
                        $arrows--;
                        echo "</th><td class=tdleft>";
-                       renderIPv4NetCell ($ainfo);
+                       renderCell ($ainfo);
                        echo "</td></tr>";
                }
                echo "<tr><th width='50%' class=tdright>&rarr;</th>";
                echo "<td class=tdleft>";
-               renderIPv4NetCell ($range);
+               renderCell ($range);
                echo "</td></tr>";
                // FIXME: get and display nested networks
                // $theitem = pickLeaf ($ipv4tree, $id);
@@ -2434,7 +2366,7 @@ function renderIPv4Network ($id)
                echo "</tr>\n";
        }
 
-       printTagTRs (makeHref(array('page'=>'ipv4space', 'tab'=>'default'))."&");
+       printTagTRs ($range, makeHref(array('page'=>'ipv4space', 'tab'=>'default'))."&");
        echo "</table><br>\n";
        finishPortlet();
 
@@ -2497,7 +2429,7 @@ function renderIPv4Network ($id)
                {
                        echo $delim . $aac2[$ref['type']];
                        echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'hl_ipv4_addr'=>$addr['ip']))."'>";
-                       echo $ref['name'] . (empty ($ref['name']) ? '' : '@');
+                       echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
                        echo "${ref['object_name']}</a>";
                        $delim = '; ';
                }
@@ -2539,8 +2471,7 @@ function renderIPv4Network ($id)
 
 function renderIPv4NetworkProperties ($id)
 {
-       showMessageOrError();
-       $netdata = getIPv4NetworkInfo ($id);
+       $netdata = spotEntity ('ipv4net', $id);
        echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
        echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
        printOpFormIntro ('editRange');
@@ -2552,11 +2483,11 @@ function renderIPv4NetworkProperties ($id)
 
 function renderIPv4Address ($dottedquad)
 {
-       global $aat;
+       global $aat, $nextorder;
        $address = getIPv4Address ($dottedquad);
        echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
        echo "<tr><td colspan=2 align=center><h1>${dottedquad}</h1></td></tr>\n";
-       if (!empty ($address['name']))
+       if (strlen ($address['name']))
                echo "<tr><td colspan=2 align=center><h2>${address['name']}</h2></td></tr>\n";
 
        echo "<tr><td class=pcleft>";
@@ -2567,7 +2498,6 @@ function renderIPv4Address ($dottedquad)
        echo "<tr><th width='50%' class=tdright>Arriving NAT connections:</th><td class=tdleft>" . count ($address['inpf']) . "</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>SLB virtual services:</th><td class=tdleft>" . count ($address['lblist']) . "</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>SLB real servers:</th><td class=tdleft>" . count ($address['rslist']) . "</td></tr>\n";
-       printTagTRs();
        echo "</table><br>\n";
        finishPortlet();
        echo "</td>\n";
@@ -2603,12 +2533,16 @@ function renderIPv4Address ($dottedquad)
        {
                startPortlet ('Virtual services (' . count ($address['lblist']) . ')');
                echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
-               echo "<tr><th>VS</th><th>name</th></tr>\n";
+               echo "<tr><th>VS</th><th>LB</th></tr>\n";
+               $order = 'odd';
                foreach ($address['lblist'] as $vsinfo)
                {
-                       echo "<tr><td class=tdleft><a href='".makeHref(array('page'=>'ipv4vs', 'vs_id'=>$vsinfo['vs_id']))."'>";
-                       echo buildVServiceName ($vsinfo) . "</a></td><td class=tdleft>";
-                       echo $vsinfo['name'] . "</td></tr>\n";
+                       echo "<tr valign=top class=row_${order}><td class=tdleft>";
+                       renderCell (spotEntity ('ipv4vs', $vsinfo['vs_id']));
+                       echo "</td><td class=tdleft>";
+                       renderLBCell ($vsinfo['object_id']);
+                       echo "</td></tr>";
+                       $order = $nextorder[$order];
                }
                echo "</table><br><br>";
                finishPortlet();
@@ -2661,7 +2595,6 @@ function renderIPv4Address ($dottedquad)
 
 function renderIPv4AddressProperties ($dottedquad)
 {
-       showMessageOrError();
        $address = getIPv4Address ($dottedquad);
        echo "<center><h1>$dottedquad</h1></center>\n";
 
@@ -2674,7 +2607,7 @@ function renderIPv4AddressProperties ($dottedquad)
        echo "></tr><tr><td class=tdleft>";
        printImageHREF ('SAVE', 'Save changes', TRUE);
        echo "</td></form><td class=tdright>";
-       if (empty ($address['name']) and $address['reserved'] == 'no')
+       if (!strlen ($address['name']) and $address['reserved'] == 'no')
                printImageHREF ('CLEAR gray');
        else
        {
@@ -2688,7 +2621,6 @@ function renderIPv4AddressProperties ($dottedquad)
 
 function renderIPv4AddressAllocations ($dottedquad)
 {
-       showMessageOrError();
        function printNewItemTR ()
        {
                global $aat;
@@ -2738,7 +2670,7 @@ function renderIPv4AddressAllocations ($dottedquad)
        echo "</table><br><br>";
 }
 
-function renderNATv4ForObject ($object_id = 0)
+function renderNATv4ForObject ($object_id)
 {
        function printNewItemTR ($alloclist)
        {
@@ -2751,8 +2683,8 @@ function renderNATv4ForObject ($object_id = 0)
 
                foreach ($alloclist as $dottedquad => $alloc)
                {
-                       $name = empty ($alloc['addrinfo']['name']) ? '' : (' (' . niftyString ($alloc['addrinfo']['name']) . ')');
-                       $osif = empty ($alloc['osif']) ? '' : ($alloc['osif'] . ': ');
+                       $name = (!isset ($alloc['addrinfo']['name']) or !strlen ($alloc['addrinfo']['name'])) ? '' : (' (' . niftyString ($alloc['addrinfo']['name']) . ')');
+                       $osif = (!isset ($alloc['osif']) or !strlen ($alloc['osif'])) ? '' : ($alloc['osif'] . ': ');
                        echo "<option value='${dottedquad}'>${osif}${dottedquad}${name}</option>";
                }
 
@@ -2768,25 +2700,23 @@ function renderNATv4ForObject ($object_id = 0)
                echo "</td></tr></form>";
        }
        
-       $info = getObjectInfo ($object_id);
-       $forwards = getNATv4ForObject ($object_id);
-       $alloclist = getObjectIPv4Allocations ($object_id);
-       showMessageOrError();
+       $focus = spotEntity ('object', $object_id);
+       amplifyCell ($focus);
        echo "<center><h2>locally performed NAT</h2></center>";
 
        echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
        echo "<tr><th></th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Comment</th><th>&nbsp;</th></tr>\n";
 
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
-               printNewItemTR ($alloclist);
-       foreach ($forwards['out'] as $pf)
+               printNewItemTR ($focus['ipv4']);
+       foreach ($focus['nat4']['out'] as $pf)
        {
                $class = 'trerror';
                $osif = '';
-               if (isset ($alloclist [$pf['localip']]))
+               if (isset ($focus['ipv4'][$pf['localip']]))
                {
-                       $class = $alloclist [$pf['localip']]['addrinfo']['class'];
-                       $osif = $alloclist [$pf['localip']]['osif'] . ': ';
+                       $class = $focus['ipv4'][$pf['localip']]['addrinfo']['class'];
+                       $osif = $focus['ipv4'][$pf['localip']]['osif'] . ': ';
                }
 
                echo "<tr class='$class'>";
@@ -2803,7 +2733,7 @@ function renderNATv4ForObject ($object_id = 0)
                printImageHREF ('delete', 'Delete NAT rule');
                echo "</a></td>";
                echo "<td>${pf['proto']}/${osif}<a href='".makeHref(array('page'=>'ipaddress', 'tab'=>'default', 'ip'=>$pf['localip']))."'>${pf['localip']}</a>:${pf['localport']}";
-               if (!empty ($pf['local_addr_name']))
+               if (strlen ($pf['local_addr_name']))
                        echo ' (' . $pf['local_addr_name'] . ')';
                echo "</td>";
                echo "<td><a href='".makeHref(array('page'=>'ipaddress', 'tab'=>'default', 'ip'=>$pf['remoteip']))."'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
@@ -2814,7 +2744,7 @@ function renderNATv4ForObject ($object_id = 0)
                if (count ($address['allocs']))
                        foreach ($address['allocs'] as $bond)
                                echo "<a href='".makeHref(array('page'=>'object', 'tab'=>'default', 'object_id'=>$bond['object_id']))."'>${bond['object_name']}(${bond['name']})</a> ";
-               elseif (!empty ($pf['remote_addr_name']))
+               elseif (strlen ($pf['remote_addr_name']))
                        echo '(' . $pf['remote_addr_name'] . ')';
                printOpFormIntro
                (
@@ -2834,15 +2764,17 @@ function renderNATv4ForObject ($object_id = 0)
                echo "</td></form></tr>";
        }
        if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
-               printNewItemTR ($alloclist);
+               printNewItemTR ($focus['ipv4']);
 
        echo "</table><br><br>";
+       if (!count ($focus['nat4']))
+               return;
 
        echo "<center><h2>arriving NAT connections</h2></center>";
        echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
        echo "<tr><th></th><th>Source</th><th>Source objects</th><th>Target</th><th>Description</th></tr>\n";
 
-       foreach ($forwards['in'] as $pf)
+       foreach ($focus['nat4']['in'] as $pf)
        {
                echo "<tr><td><a href='".
                        makeHrefProcess(array(
@@ -2868,7 +2800,6 @@ function renderNATv4ForObject ($object_id = 0)
 
 function renderAddMultipleObjectsForm ()
 {
-       showMessageOrError();
        $typelist = getObjectTypeList();
        $typelist[0] = 'select type...';
        $max = getConfigVar ('MASSCOUNT');
@@ -2892,7 +2823,7 @@ function renderAddMultipleObjectsForm ()
                if ($i == 0)
                {
                        echo "<td valign=top rowspan=${max}>";
-                       renderNewEntityTags();
+                       renderNewEntityTags ('object');
                        echo "</td>\n";
                }
                echo "</tr>\n";
@@ -2911,7 +2842,7 @@ function renderAddMultipleObjectsForm ()
        echo "</td></tr>";
        echo "<tr><th>Tags</th></tr>";
        echo "<tr><td valign=top>";
-       renderNewEntityTags();
+       renderNewEntityTags ('object');
        echo "</td></tr>";
        echo "<tr><td colspan=2><input type=submit name=got_very_fast_data value='Go!'></td></tr></table>\n";
        echo "</form>\n";
@@ -2930,7 +2861,7 @@ function renderSearchResults ()
 {
        global $root;
        $terms = trim ($_REQUEST['q']);
-       if (empty ($terms))
+       if (!strlen ($terms))
        {
                showError ('Search string cannot be empty.', __FUNCTION__);
                return;
@@ -2983,7 +2914,7 @@ function renderSearchResults ()
                {
                        $nhits++;
                        $lasthit = 'ipv4network';
-                       $summary['ipv4network'][] = getIPv4NetworkInfo ($tmp);
+                       $summary['ipv4network'][] = spotEntity ('ipv4net', $tmp);
                }
        }
        else
@@ -3038,6 +2969,13 @@ function renderSearchResults ()
                        $lasthit = 'file';
                        $summary['file'] = $tmp;
                }
+               $tmp = getRackSearchResult ($terms);
+               if (count ($tmp))
+               {
+                       $nhits += count ($tmp);
+                       $lasthit = 'rack';
+                       $summary['rack'] = $tmp;
+               }
        }
        if ($nhits == 0)
                echo "<center><h2>Nothing found for '${terms}'</h2></center>";
@@ -3085,6 +3023,9 @@ function renderSearchResults ()
                        case 'file':
                                echo "<script language='Javascript'>document.location='${root}?page=file&file_id=${record['id']}';//</script>";
                                break;
+                       case 'rack':
+                               echo "<script language='Javascript'>document.location='${root}?page=rack&rack_id=${record['id']}';//</script>";
+                               break;
                }
                return;
        }
@@ -3117,10 +3058,10 @@ function renderSearchResults ()
                                case 'ipv4network':
                                        startPortlet ("<a href='${root}?page=ipv4space'>IPv4 networks</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       foreach ($what as $netinfo)
+                                       foreach ($what as $cell)
                                        {
                                                echo "<tr class=row_${order} valign=top><td>";
-                                               renderIPv4NetCell ($netinfo);
+                                               renderCell ($cell);
                                                echo "</td></tr>\n";
                                                $order = $nextorder[$order];
                                        }
@@ -3149,10 +3090,10 @@ function renderSearchResults ()
                                case 'ipv4rspool':
                                        startPortlet ("<a href='${root}?page=ipv4rsplist'>RS pools</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       foreach ($what as $rspool)
+                                       foreach ($what as $cell)
                                        {
                                                echo "<tr class=row_${order}><td class=tdleft>";
-                                               renderRSPoolCell ($rspool['pool_id'], $rspool['name']);
+                                               renderCell ($cell);
                                                echo "</td></tr>";
                                                $order = $nextorder[$order];
                                        }
@@ -3162,10 +3103,10 @@ function renderSearchResults ()
                                case 'ipv4vs':
                                        startPortlet ("<a href='${root}?page=ipv4vslist'>Virtual services</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       foreach ($what as $vsinfo)
+                                       foreach ($what as $cell)
                                        {
                                                echo "<tr class=row_${order}><td class=tdleft>";
-                                               renderIPv4VSCell ($vsinfo);
+                                               renderCell ($cell);
                                                echo "</td></tr>";
                                                $order = $nextorder[$order];
                                        }
@@ -3188,10 +3129,23 @@ function renderSearchResults ()
                                case 'file':
                                        startPortlet ("<a href='${root}?page=files'>Files</a>");
                                        echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
-                                       foreach ($what as $item)
+                                       foreach ($what as $cell)
                                        {
                                                echo "<tr class=row_${order}><td class=tdleft>";
-                                               renderFileCell ($item);
+                                               renderCell ($cell);
+                                               echo "</td></tr>";
+                                               $order = $nextorder[$order];
+                                       }
+                                       echo '</table>';
+                                       finishPortlet();
+                                       break;
+                               case 'rack':
+                                       startPortlet ("<a href='${root}?page=rackspace'>Racks</a>");
+                                       echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
+                                       foreach ($what as $cell)
+                                       {
+                                               echo "<tr class=row_${order}><td class=tdleft>";
+                                               renderCell ($cell);
                                                echo "</td></tr>";
                                                $order = $nextorder[$order];
                                        }
@@ -3204,7 +3158,7 @@ function renderSearchResults ()
 
 // This function prints a table of checkboxes to aid the user in toggling mount atoms
 // from one state to another. The first argument is rack data as
-// produced by getRackData(), the second is the value used for the 'unckecked' state
+// produced by amplifyCell(), the second is the value used for the 'unckecked' state
 // and the third is the value used for 'checked' state.
 // Usage contexts:
 // for mounting an object:             printAtomGrid ($data, 'F', 'T')
@@ -3285,7 +3239,6 @@ function renderUserListEditor ()
        }
        $accounts = listCells ('user');
        startPortlet ('User accounts (' . count ($accounts) . ')');
-       showMessageOrError();
        echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
        echo "<tr><th>Username</th><th>Real name</th><th>Password</th><th>&nbsp;</th></tr>\n";
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
@@ -3318,7 +3271,6 @@ function renderPortMapEditor ()
 function renderPortMap ($editable = FALSE)
 {
        global $nextorder;
-       showMessageOrError();
        startPortlet ("Port compatibility map");
        $ptlist = getPortTypes();
        $pclist = getPortCompat();
@@ -3369,16 +3321,12 @@ function renderConfigMainpage ()
 
 function renderRackPage ($rack_id)
 {
-       if ($rack_id == 0)
+       if (NULL == ($rackData = spotEntity ('rack', $rack_id)))
        {
-               showError ('Invalid argument', __FUNCTION__);
-               return;
-       }
-       if (($rackData = getRackData ($rack_id)) == NULL)
-       {
-               showError ('getRackData() failed', __FUNCTION__);
+               showError ('Rack not found', __FUNCTION__);
                return;
        }
+       amplifyCell ($rackData);
        echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
 
        // Left column with information.
@@ -3400,11 +3348,10 @@ function renderRackPage ($rack_id)
 function renderDictionary ()
 {
        global $nextorder;
-       $dict = getDict (TRUE);
        echo '<ul>';
-       foreach ($dict as $chapter_no => $chapter)
+       foreach (getChapterList() as $chapter_no => $chapter)
        {
-               $wc = count ($chapter['word']);
+               $wc = $chapter['wordc'];
                echo "<li><a href='".makeHref(array('page'=>'chapter', 'chapter_no'=>$chapter_no))."'>${chapter['name']}</a>";
                echo " (${wc} records)</li>";
        }
@@ -3457,7 +3404,6 @@ function renderChapterEditor ($tgt_chapter_no)
                echo '</td></tr></form>';
        }
        $dict = getDict();
-       showMessageOrError();
        echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
        foreach ($dict as $chapter_no => $chapter)
        {
@@ -3517,8 +3463,7 @@ function renderChaptersEditor ()
                printImageHREF ('create', 'Add new', TRUE, 101);
                echo '</td></tr></form>';
        }
-       showMessageOrError();
-       $dict = getDict();
+       $dict = getChapterList();
        foreach (array_keys ($dict) as $chapter_no)
                $dict[$chapter_no]['mapped'] = FALSE;
        foreach (getAttrMap() as $attrinfo)
@@ -3529,11 +3474,11 @@ function renderChaptersEditor ()
        echo '<tr><th>&nbsp;</th><th>Chapter name</th><th>Words</th><th>&nbsp;</th></tr>';
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
                printNewItemTR();
-       foreach ($dict as $chapter)
+       foreach ($dict as $chapter_id => $chapter)
        {
-               $wordcount = count ($chapter['word']);
-               $sticky = $chapter['sticky'];
-               printOpFormIntro ('upd', array ('chapter_no' => $chapter['no']));
+               $wordcount = $chapter['wordc'];
+               $sticky = $chapter['sticky'] == 'yes';
+               printOpFormIntro ('upd', array ('chapter_no' => $chapter_id));
                echo '<tr>';
                echo '<td>';
                if ($sticky)
@@ -3544,7 +3489,7 @@ function renderChaptersEditor ()
                        printImageHREF ('nodestroy', 'used in attribute map');
                else
                {
-                       echo "<a href='".makeHrefProcess(array('op'=>'del', 'chapter_no'=>$chapter['no']))."'>";
+                       echo "<a href='".makeHrefProcess(array('op'=>'del', 'chapter_no'=>$chapter_id))."'>";
                        printImageHREF ('destroy', 'Remove chapter');
                        echo "</a>";
                }
@@ -3608,7 +3553,6 @@ function renderEditAttributesForm ()
                echo '</td></tr></form>';
        }
        $attrMap = getAttrMap();
-       showMessageOrError();
        startPortlet ('Optional attributes');
        echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
        echo '<tr><th>&nbsp;</th><th>Name</th><th>Type</th><th>&nbsp;</th></tr>';
@@ -3617,11 +3561,16 @@ function renderEditAttributesForm ()
        foreach ($attrMap as $attr)
        {
                printOpFormIntro ('upd', array ('attr_id' => $attr['id']));
-               echo '<tr>';
-               echo "<td><a href='".makeHrefProcess(array('op'=>'del', 'attr_id'=>$attr['id']))."'>";
-               printImageHREF ('delete', 'Remove attribute');
-               echo '</a></td>';
-               echo "<td><input type=text name=attr_name value='${attr['name']}'></td>";
+               echo '<tr><td>';
+               if (count ($attr['application']))
+                       printImageHREF ('nodelete', count ($attr['application']) . ' reference(s) in attribute map');
+               else
+               {
+                       echo "<a href='".makeHrefProcess(array('op'=>'del', 'attr_id'=>$attr['id']))."'>";
+                       printImageHREF ('delete', 'Remove attribute');
+                       echo '</a>';
+               }
+               echo "</td><td><input type=text name=attr_name value='${attr['name']}'></td>";
                echo "<td class=tdleft>${attr['type']}</td><td>";
                printImageHREF ('save', 'Save changes', TRUE);
                echo '</td></tr>';
@@ -3651,36 +3600,34 @@ function renderEditAttrMapForm ()
                echo '<td>';
                printSelect (getObjectTypeList(), 'objtype_id', NULL, 101);
                echo '</td>';
-               $dict = getDict();
                echo '<td><select name=chapter_no tabindex=102>';
-               foreach ($dict as $chapter)
-                       if (!$chapter['sticky'])
-                               echo "<option value='${chapter['no']}'>${chapter['name']}</option>";
+               foreach (getChapterList() as $chapter)
+                       if ($chapter['sticky'] != 'yes')
+                               echo "<option value='${chapter['id']}'>${chapter['name']}</option>";
                echo '</select></td><td>';
                printImageHREF ('add', '', TRUE, 103);
                echo '</td></tr>';
                echo '</form>';
        }
        $attrMap = getAttrMap();
-       showMessageOrError();
        startPortlet ('Attribute map');
        echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
        echo '<tr><th>&nbsp;</th><th>Attribute name</th><th>Object type</th><th>Dictionary chapter</th><th>&nbsp;</th></tr>';
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
                printNewItemTR ($attrMap);
        foreach ($attrMap as $attr)
-       {
-               if (count ($attr['application']) == 0)
-                       continue;
                foreach ($attr['application'] as $app)
                {
-                       echo '<tr>';
-                       echo '<td>';
-                       echo "<a href='".makeHrefProcess(array('op'=>'del', 'attr_id'=>$attr['id'], 'objtype_id'=>$app['objtype_id']))."'>";
-                       printImageHREF ('delete', 'Remove mapping');
-                       echo "</a>";
-                       echo '</td>';
-                       echo "<td>${attr['name']}</td>";
+                       echo '<tr><td>';
+                       if ($app['refcnt'])
+                               printImageHREF ('nodelete', $app['refcnt'] . ' value(s) stored for objects');
+                       else
+                       {
+                               echo "<a href='".makeHrefProcess(array('op'=>'del', 'attr_id'=>$attr['id'], 'objtype_id'=>$app['objtype_id']))."'>";
+                               printImageHREF ('delete', 'Remove mapping');
+                               echo "</a>";
+                       }
+                       echo "</td><td>${attr['name']}</td>";
                        echo "<td>${app['objtype_name']}</td>";
                        echo "<td>";
                        if ($attr['type'] == 'dict')
@@ -3689,7 +3636,6 @@ function renderEditAttrMapForm ()
                                echo '&nbsp;';
                        echo "</td></tr>\n";
                }
-       }
        if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
                printNewItemTR ($attrMap);
        echo "</table>\n";
@@ -3713,7 +3659,7 @@ function getImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
                        "src='${root}${img['path']}' " .
                        "border=0 " .
                        ($tabindex ? "tabindex=${tabindex}" : '') .
-                       (empty ($title) ? '' : " title='${title}'") . // JT: Add title to input hrefs too
+                       (!strlen ($title) ? '' : " title='${title}'") . // JT: Add title to input hrefs too
                        ">";
        else
                return
@@ -3722,7 +3668,7 @@ function getImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
                        "width=${img['width']} " .
                        "height=${img['height']} " .
                        "border=0 " .
-                       (empty ($title) ? '' : "title='${title}'") .
+                       (!strlen ($title) ? '' : "title='${title}'") .
                        ">";
 }
 
@@ -3750,6 +3696,12 @@ function renderSystemReports ()
                        'func' => 'getRackspaceStats'
                ),
                array
+               (
+                       'title' => 'Files',
+                       'type' => 'counters',
+                       'func' => 'getFileStats'
+               ),
+               array
                (
                        'title' => 'Tags top-50',
                        'type' => 'custom',
@@ -3795,12 +3747,6 @@ function renderIPv4Reports ()
                        'type' => 'counters',
                        'func' => 'getIPv4Stats'
                ),
-               array
-               (
-                       'title' => 'Lost addresses',
-                       'type' => 'custom',
-                       'func' => 'getLostIPv4Addresses'
-               ),
        );
        renderReports ($tmp);
 }
@@ -3861,7 +3807,6 @@ function dragon ()
 function renderUIConfig ()
 {
        global $configCache, $nextorder;
-       showMessageOrError();
        startPortlet ('Current configuration');
        echo '<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center width="50%">';
        echo '<tr><th class=tdleft>Option</th><th class=tdleft>Value</th></tr>';
@@ -3882,7 +3827,6 @@ function renderUIConfig ()
 function renderUIConfigEditForm ()
 {
        global $configCache;
-       showMessageOrError();
        startPortlet ('Current configuration');
        echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='50%'>\n";
        echo "<tr><th class=tdleft>Option</th>";
@@ -3910,9 +3854,8 @@ function renderUIConfigEditForm ()
 
 // This function queries the gateway about current VLAN configuration and
 // renders a form suitable for submit. Ah, and it does submit processing as well.
-function renderVLANMembership ($object_id = 0)
+function renderVLANMembership ($object_id)
 {
-       showMessageOrError();
        $data = getSwitchVLANs ($object_id);
        if ($data === NULL)
        {
@@ -4048,14 +3991,8 @@ function renderVLANMembership ($object_id = 0)
        echo '</td></tr></table>';
 }
 
-function renderSNMPPortFinder ($object_id = 0)
+function renderSNMPPortFinder ($object_id)
 {
-       showMessageOrError();
-       if ($object_id <= 0)
-       {
-               showError ('Invalid argument', __FUNCTION__);
-               return;
-       }
        printOpFormIntro ('querySNMPData');
        if (!extension_loaded ('snmp'))
        {
@@ -4063,11 +4000,15 @@ function renderSNMPPortFinder ($object_id = 0)
        }
        else
        {
+               $snmpcomm = getConfigVar('DEFAULT_SNMP_COMMUNITY');
+               if (empty($snmpcomm))
+                       $snmpcomm = 'public';
+
                echo "<p align=center>
 This object has no ports listed, that's why you see this form. If you supply a SNMP community,
 I can try to automatically harvest the data. As soon as at least one port is added,
 this tab will not be seen any more. Good luck.<br>\n";
-               echo "<input type=text name=community value='public'>\n";
+               echo "<input type=text name=community value='" . $snmpcomm . "'>\n";
                echo "<input type=submit name='do_scan' value='Go!'> \n";
                echo "</form></p>\n";
        }
@@ -4081,14 +4022,8 @@ function renderUIResetForm()
        echo "</form>";
 }
 
-function renderLVSConfig ($object_id = 0)
+function renderLVSConfig ($object_id)
 {
-       showMessageOrError();
-       if ($object_id <= 0)
-       {
-               showError ('Invalid argument', __FUNCTION__);
-               return;
-       }
        echo '<br>';
        printOpFormIntro ('submitSLBConfig');
        echo "<center><input type=submit value='Submit for activation'></center>";
@@ -4101,32 +4036,28 @@ function renderLVSConfig ($object_id = 0)
 function renderVirtualService ($vsid)
 {
        global $nextorder;
-       if ($vsid <= 0)
-       {
-               showError ('Invalid argument', __FUNCTION__);
-               return;
-       }
-       $vsinfo = getVServiceInfo ($vsid);
+       $vsinfo = spotEntity ('ipv4vs', $vsid);
+       amplifyCell ($vsinfo);
        echo '<table border=0 class=objectview cellspacing=0 cellpadding=0>';
-       if (!empty ($vsinfo['name']))
+       if (strlen ($vsinfo['name']))
                echo "<tr><td colspan=2 align=center><h1>${vsinfo['name']}</h1></td></tr>\n";
        echo '<tr>';
 
        echo '<td class=pcleft>';
        startPortlet ('Frontend');
        echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
-       if (!empty ($vsinfo['name']))
+       if (strlen ($vsinfo['name']))
                echo "<tr><th width='50%' class=tdright>Name:</th><td class=tdleft>${vsinfo['name']}</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Protocol:</th><td class=tdleft>${vsinfo['proto']}</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Virtual IP address:</th><td class=tdleft><a href='".makeHref(array('page'=>'ipaddress', 'tab'=>'default', 'ip'=>$vsinfo['vip']))."'>${vsinfo['vip']}</a></td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Virtual port:</th><td class=tdleft>${vsinfo['vport']}</td></tr>\n";
-       printTagTRs (makeHref(array('page'=>'ipv4vslist', 'tab'=>'default'))."&");
-       if (!empty ($vsinfo['vsconfig']))
+       printTagTRs ($vsinfo, makeHref(array('page'=>'ipv4vslist', 'tab'=>'default'))."&");
+       if (strlen ($vsinfo['vsconfig']))
        {
                echo "<tr><th class=slbconf>VS configuration:</th><td>&nbsp;</td></tr>";
                echo "<tr><td colspan=2 class='dashed slbconf'>${vsinfo['vsconfig']}</td></tr>\n";
        }
-       if (!empty ($vsinfo['rsconfig']))
+       if (strlen ($vsinfo['rsconfig']))
        {
                echo "<tr><th class=slbconf>RS configuration:</th><td class=tdleft>&nbsp;</td></tr>\n";
                echo "<tr><td colspan=2 class='dashed slbconf'>${vsinfo['rsconfig']}</td></tr>\n";
@@ -4146,11 +4077,11 @@ function renderVirtualService ($vsid)
                // Pool info
                echo '<table width=100%>';
                echo "<tr><td colspan=2>";
-               renderRSPoolCell ($pool_id, $poolInfo['name']);
+               renderCell (spotEntity ('ipv4rspool', $pool_id));
                echo "</td></tr>";
-               if (!empty ($poolInfo['vsconfig']))
+               if (strlen ($poolInfo['vsconfig']))
                        echo "<tr><th>VS config</th><td class='dashed slbconf'>${poolInfo['vsconfig']}</td></tr>";
-               if (!empty ($poolInfo['rsconfig']))
+               if (strlen ($poolInfo['rsconfig']))
                        echo "<tr><th>RS config</th><td class='dashed slbconf'>${poolInfo['rsconfig']}</td></tr>";
                echo '</table>';
                echo '</td><td>';
@@ -4165,9 +4096,9 @@ function renderVirtualService ($vsid)
                                echo "<tr><td colspan=2>";
                                renderLBCell ($object_id);
                                echo '</td></tr>';
-                               if (!empty ($lbInfo['vsconfig']))
+                               if (strlen ($lbInfo['vsconfig']))
                                        echo "<tr><th>VS config</th><td class='dashed slbconf'>${lbInfo['vsconfig']}</td></tr>";
-                               if (!empty ($lbInfo['rsconfig']))
+                               if (strlen ($lbInfo['rsconfig']))
                                        echo "<tr><th>RS config</th><td class='dashed slbconf'>${lbInfo['rsconfig']}</td></tr>";
                        }
                        echo '</table>';
@@ -4177,8 +4108,8 @@ function renderVirtualService ($vsid)
        }
        echo "</table>\n";
        finishPortlet ();
-       echo '</td>';
-
+       echo '</td></tr><tr><td colspan=2>';
+       renderFilesPortlet ('ipv4vs', $vsid);
        echo '</tr><table>';
 }
 
@@ -4187,19 +4118,14 @@ function renderProgressBar ($percentage = 0, $theme = '')
        global $root;
        $done = ((int) ($percentage * 100));
        echo "<img width=100 height=10 border=0 title='${done}%' src='${root}render_image.php?img=progressbar&done=${done}";
-       echo (empty ($theme) ? '' : "&theme=${theme}") . "'>";
+       echo (!strlen ($theme) ? '' : "&theme=${theme}") . "'>";
 }
 
-function renderRSPoolServerForm ($pool_id = 0)
+function renderRSPoolServerForm ($pool_id)
 {
        global $nextorder;
-       if ($pool_id <= 0)
-       {
-               showError ('Invalid pool_id', __FUNCTION__);
-               return;
-       }
-       showMessageOrError();
-       $poolInfo = getRSPoolInfo ($pool_id);
+       $poolInfo = spotEntity ('ipv4rspool', $pool_id);
+       amplifyCell ($poolInfo);
 
        if (($rsc = count ($poolInfo['rslist'])))
        {
@@ -4269,12 +4195,11 @@ function renderRSPoolServerForm ($pool_id = 0)
        finishPortlet();
 }
 
-function renderRSPoolLBForm ($pool_id = 0)
+function renderRSPoolLBForm ($pool_id)
 {
        global $nextorder;
-       showMessageOrError();
-
-       $poolInfo = getRSPoolInfo ($pool_id);
+       $poolInfo = spotEntity ('ipv4rspool', $pool_id);
+       amplifyCell ($poolInfo);
 
        if (count ($poolInfo['lblist']))
        {
@@ -4292,7 +4217,7 @@ function renderRSPoolLBForm ($pool_id = 0)
                                echo "<td class=tdleft>";
                                renderLBCell ($object_id);
                                echo "</td><td class=tdleft>";
-                               renderVSCell ($vs_id);
+                               renderCell (spotEntity ('ipv4vs', $vs_id));
                                echo "</td><td><textarea name=vsconfig>${configs['vsconfig']}</textarea></td>";
                                echo "<td><textarea name=rsconfig>${configs['rsconfig']}</textarea></td><td>";
                                printImageHREF ('SAVE', 'Save changes', TRUE);
@@ -4318,11 +4243,11 @@ function renderRSPoolLBForm ($pool_id = 0)
        finishPortlet();
 }
 
-function renderVServiceLBForm ($vs_id = 0)
+function renderVServiceLBForm ($vs_id)
 {
        global $nextorder;
-       showMessageOrError();
-       $vsinfo = getVServiceInfo ($vs_id);
+       $vsinfo = spotEntity ('ipv4vs', $vs_id);
+       amplifyCell ($vsinfo);
 
        if (count ($vsinfo['rspool']))
        {
@@ -4340,7 +4265,7 @@ function renderVServiceLBForm ($vs_id = 0)
                                echo "<td class=tdleft>";
                                renderLBCell ($object_id);
                                echo "</td><td class=tdleft>";
-                               renderRSPoolCell ($pool_id, $rspinfo['name']);
+                               renderCell (spotEntity ('ipv4rspool', $pool_id));
                                echo "</td><td><textarea name=vsconfig>${configs['vsconfig']}</textarea></td>";
                                echo "<td><textarea name=rsconfig>${configs['rsconfig']}</textarea></td><td>";
                                printImageHREF ('SAVE', 'Save changes', TRUE);
@@ -4366,39 +4291,35 @@ function renderVServiceLBForm ($vs_id = 0)
        finishPortlet();
 }
 
-function renderRSPool ($pool_id = 0)
+function renderRSPool ($pool_id)
 {
        global $nextorder;
-       if ($pool_id <= 0)
-       {
-               showError ('Invalid pool_id', __FUNCTION__);
-               return;
-       }
-       $poolInfo = getRSPoolInfo ($pool_id);
+       $poolInfo = spotEntity ('ipv4rspool', $pool_id);
        if ($poolInfo == NULL)
        {
-               showError ('getRSPoolInfo() returned NULL', __FUNCTION__);
+               showError ('Could not load data!', __FUNCTION__);
                return;
        }
+       amplifyCell ($poolInfo);
 
        echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
-       if (!empty ($poolInfo['name']))
+       if (strlen ($poolInfo['name']))
                echo "<tr><td colspan=2 align=center><h1>{$poolInfo['name']}</h1></td></tr>";
        echo "<tr><td class=pcleft>\n";
 
        startPortlet ('Summary');
        echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
-       if (!empty ($poolInfo['name']))
+       if (strlen ($poolInfo['name']))
                echo "<tr><th width='50%' class=tdright>Pool name:</th><td class=tdleft>${poolInfo['name']}</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Real servers:</th><td class=tdleft>" . count ($poolInfo['rslist']) . "</td></tr>\n";
        echo "<tr><th width='50%' class=tdright>Load balancers:</th><td class=tdleft>" . count ($poolInfo['lblist']) . "</td></tr>\n";
-       printTagTRs (makeHref(array('page'=>'ipv4rsplist', 'tab'=>'default'))."&");
-       if (!empty ($poolInfo['vsconfig']))
+       printTagTRs ($poolInfo, makeHref(array('page'=>'ipv4rsplist', 'tab'=>'default'))."&");
+       if (strlen ($poolInfo['vsconfig']))
        {
                echo "<tr><th width='50%' class=tdright>VS configuration:</th><td>&nbsp;</td></tr>\n";
                echo "<tr><td colspan=2 class='dashed slbconf'>${poolInfo['vsconfig']}</td></tr>\n";
        }
-       if (!empty ($poolInfo['rsconfig']))
+       if (strlen ($poolInfo['rsconfig']))
        {
                echo "<tr><th width='50%' class=tdright>RS configuration:</th><td>&nbsp;</td></tr>\n";
                echo "<tr><td colspan=2 class='dashed slbconf'>${poolInfo['rsconfig']}</td></tr>\n";
@@ -4414,7 +4335,7 @@ function renderRSPool ($pool_id = 0)
                foreach ($vslist as $vs_id => $configs)
        {
                echo "<tr valign=top class=row_${order}><td class=tdleft><a href='".makeHref(array('page'=>'ipv4vs', 'vs_id'=>$vs_id))."'>";
-               renderVSCell ($vs_id);
+               renderCell (spotEntity ('ipv4vs', $vs_id));
                echo "</td><td>";
                renderLBCell ($object_id);
                echo "</td><td class=slbconf>${configs['vsconfig']}</td>";
@@ -4441,7 +4362,8 @@ function renderRSPool ($pool_id = 0)
        }
        echo "</table>\n";
        finishPortlet();
-
+       echo "</td></tr><tr><td colspan=2>\n";
+       renderFilesPortlet ('ipv4rspool', $pool_id);
        echo "</td></tr></table>\n";
 }
 
@@ -4453,7 +4375,6 @@ function renderVSList ()
 function renderVSListEditForm ()
 {
        global $nextorder;
-       showMessageOrError();
        $protocols = array ('TCP' => 'TCP', 'UDP' => 'UDP');
 
        startPortlet ('Add new');
@@ -4472,7 +4393,7 @@ function renderVSListEditForm ()
        printImageHREF ('CREATE', 'create virtual service', TRUE);
        echo "</td></tr><tr><th>VS configuration</th><td colspan=4 class=tdleft><textarea name=vsconfig rows=10 cols=80></textarea></td>\n";
        echo "<td rowspan=2><h3>assign tags</h3>";
-       renderNewEntityTags();
+       renderNewEntityTags ('ipv4vs');
        echo "</td></tr>";
        echo "<tr><th>RS configuration</th><td colspan=4 class=tdleft><textarea name=rsconfig rows=10 cols=80></textarea></td></tr>\n";
        echo "</table>";
@@ -4523,8 +4444,6 @@ function renderRSPoolList ()
 function editRSPools ()
 {
        global $nextorder;
-       showMessageOrError();
-
        startPortlet ('Add new');
        printOpFormIntro ('add');
        echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
@@ -4533,7 +4452,7 @@ function editRSPools ()
        printImageHREF ('CREATE', 'create real server pool', TRUE);
        echo "</td></tr><tr><th>VS configuration</th><td><textarea name=vsconfig rows=10 cols=80></textarea></td>";
        echo "<td rowspan=2><h3>assign tags</h3>";
-       renderNewEntityTags();
+       renderNewEntityTags ('ipv4rspool');
        echo "</td></tr>";
        echo "<tr><th>RS configuration</th><td><textarea name=rsconfig rows=10 cols=80></textarea></td></tr>";
        echo "</table></form>";
@@ -4587,7 +4506,7 @@ function renderRealServerList ()
                        $last_pool_id = $rsinfo['rspool_id'];
                }
                echo "<tr valign=top class=row_${order}><td><a href='".makeHref(array('page'=>'ipv4rspool', 'pool_id'=>$rsinfo['rspool_id']))."'>";
-               echo empty ($pool_list[$rsinfo['rspool_id']]['name']) ? 'ANONYMOUS' : $pool_list[$rsinfo['rspool_id']]['name'];
+               echo !strlen ($pool_list[$rsinfo['rspool_id']]['name']) ? 'ANONYMOUS' : $pool_list[$rsinfo['rspool_id']]['name'];
                echo '</a></td><td align=center>';
                if ($rsinfo['inservice'] == 'yes')
                        printImageHREF ('inservice', 'in service');
@@ -4606,29 +4525,22 @@ function renderLBList ()
        global $nextorder;
        echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
        echo "<tr><th>Object</th><th>RS pools configured</th></tr>";
-       $oicache = array();
        $order = 'odd';
        foreach (getLBList() as $object_id => $poolcount)
        {
-               if (!isset ($oicache[$object_id]))
-                       $oicache[$object_id] = getObjectInfo ($object_id);
+               $oi = spotEntity ('object', $object_id);
                echo "<tr valign=top class=row_${order}><td><a href='".makeHref(array('page'=>'object', 'object_id'=>$object_id))."'>";
-               echo $oicache[$object_id]['dname'] . '</a></td>';
+               echo $oi['dname'] . '</a></td>';
                echo "<td>${poolcount}</td></tr>";
                $order = $nextorder[$order];
        }
        echo "</table>";
 }
 
-function renderRSPoolRSInServiceForm ($pool_id = 0)
+function renderRSPoolRSInServiceForm ($pool_id)
 {
-       if ($pool_id <= 0)
-       {
-               showError ('Invalid pool_id', __FUNCTION__);
-               return;
-       }
-       showMessageOrError();
-       $poolInfo = getRSPoolInfo ($pool_id);
+       $poolInfo = spotEntity ('ipv4rspool', $pool_id);
+       amplifyCell ($poolInfo);
        printOpFormIntro ('upd', array ('rscount' => count ($poolInfo['rslist'])));
        echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
        echo "<tr><th>RS address</th><th>RS port</th><th>RS configuration</th><th>in service</th></tr>\n";
@@ -4646,21 +4558,15 @@ function renderRSPoolRSInServiceForm ($pool_id = 0)
        echo "</td></tr></table>\n</form>";
 }
 
-function renderLivePTR ($id = 0)
+function renderLivePTR ($id)
 {
-       if ($id == 0)
-       {
-               showError ("Invalid argument", __FUNCTION__);
-               return;
-       }
-       showMessageOrError();
        if (isset($_REQUEST['pg']))
                $page = $_REQUEST['pg'];
        else
                $page=0;
        global $pageno, $tabno;
        $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
-       $range = getIPv4NetworkInfo ($id);
+       $range = spotEntity ('ipv4net', $id);
        loadIPv4AddrList ($range);
        echo "<center><h1>${range['ip']}/${range['mask']}</h1><h2>${range['name']}</h2></center>\n";
 
@@ -4711,13 +4617,13 @@ function renderLivePTR ($id = 0)
                $print_cbox = FALSE;
                if ($addr['name'] == $ptrname)
                {
-                       if (!empty ($ptrname))
+                       if (strlen ($ptrname))
                        {
                                echo ' class=trok';
                                $cnt_match++;
                        }
                }
-               elseif (empty ($addr['name']) or empty ($ptrname))
+               elseif (!strlen ($addr['name']) or !strlen ($ptrname))
                {
                        echo ' class=trwarning';
                        $print_cbox = TRUE;
@@ -4730,7 +4636,7 @@ function renderLivePTR ($id = 0)
                        $cnt_mismatch++;
                }
                echo "><td class='tdleft";
-               if (!empty ($range['addrlist'][$ip]['class']))
+               if (isset ($range['addrlist'][$ip]['class']) and strlen ($range['addrlist'][$ip]['class']))
                        echo ' ' . $range['addrlist'][$ip]['class'];
                echo "'><a href='".makeHref(array('page'=>'ipaddress', 'ip'=>$straddr))."'>${straddr}</a></td>";
                echo "<td class=tdleft>${addr['name']}</td><td class=tdleft>${ptrname}</td><td>";
@@ -4762,17 +4668,9 @@ function renderLivePTR ($id = 0)
        echo "</td></tr></table>\n";
 }
 
-function renderAutoPortsForm ($object_id = 0)
+function renderAutoPortsForm ($object_id)
 {
-       if ($object_id <= 0)
-       {
-               showError ('Invalid object_id', __FUNCTION__);
-               return;
-       }
-       // If the below call has any data to display, the non-default redirection from the generator
-       // has failed. Don't ignore the message log anyway.
-       showMessageOrError();
-       $info = getObjectInfo ($object_id);
+       $info = spotEntity ('object', $object_id);
        $ptlist = readChapter ('PortType');
        echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center'>\n";
        echo "<caption>The following ports can be quickly added:</caption>";
@@ -4791,12 +4689,12 @@ function renderTagRowForViewer ($taginfo, $level = 0)
        $self = __FUNCTION__;
        if (!count ($taginfo['kids']))
                $level++; // Shift instead of placing a spacer. This won't impact any nested nodes.
+       $refc = array_sum ($taginfo['refcnt']);
        echo "<tr><td align=left style='padding-left: " . ($level * 16) . "px;'>";
        if (count ($taginfo['kids']))
                printImageHREF ('node-expanded-static');
-       echo '<span title="id = ' . $taginfo['id'] . '">';
-       echo $taginfo['tag'] . '</span>';
-       echo "</td></tr>\n";
+       echo '<span title="id = ' . $taginfo['id'] . '">' . $taginfo['tag'];
+       echo ($refc ? " <i>(${refc})</i>" : '') . '</span></td></tr>';
        foreach ($taginfo['kids'] as $kid)
                $self ($kid, $level + 1);
 }
@@ -4868,7 +4766,6 @@ function renderTagTreeEditor ()
                echo "</td></tr></form>\n";
        }
        global $taglist, $tagtree;
-       showMessageOrError();
 
        $otags = getOrphanedTags();
        if (count ($otags))
@@ -4907,7 +4804,7 @@ function renderTagTreeEditor ()
        finishPortlet();
 }
 
-function renderTagCheckbox ($inputname, $preselect, $taginfo, $level = 0)
+function renderTagCheckbox ($inputname, $preselect, $taginfo, $refcnt_realm = '', $level = 0)
 {
        $self = __FUNCTION__;
        if (tagOnChain ($taginfo, $preselect))
@@ -4921,28 +4818,24 @@ function renderTagCheckbox ($inputname, $preselect, $taginfo, $level = 0)
                $class = 'tagbox';
        }
        echo "<tr><td colspan=2 class=${class} style='padding-left: " . ($level * 16) . "px;'>";
-       echo "<input type=checkbox name='${inputname}[]' value='${taginfo['id']}'${selected}> ";
-       echo $taginfo['tag'] . "</td></tr>\n";
+       echo "<label><input type=checkbox name='${inputname}[]' value='${taginfo['id']}'${selected}> ";
+       echo $taginfo['tag'];
+       if (strlen ($refcnt_realm) and isset ($taginfo['refcnt'][$refcnt_realm]))
+               echo ' <i>(' . $taginfo['refcnt'][$refcnt_realm] . ')</i>';
+       echo "</label></td></tr>\n";
        foreach ($taginfo['kids'] as $kid)
-               $self ($inputname, $preselect, $kid, $level + 1);
+               $self ($inputname, $preselect, $kid, $refcnt_realm, $level + 1);
 }
 
-function renderEntityTags ($entity_id = 0)
+function renderEntityTags ($entity_id)
 {
-       global $tagtree, $target_given_tags, $pageno, $page, $target_given_tags;
-       if ($entity_id <= 0)
-       {
-               showError ('Invalid or missing arguments', __FUNCTION__);
-               return;
-       }
-       showMessageOrError();
-       $bypass_name = $page[$pageno]['bypass'];
+       global $tagtree, $target_given_tags, $pageno, $etype_by_pageno, $target_given_tags;
        startPortlet ('Tag list');
        echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
        printOpFormIntro ('saveTags');
        // Show a tree of tags with preselection, which matches current chain.
        foreach ($tagtree as $taginfo)
-               renderTagCheckbox ('taglist', $target_given_tags, $taginfo);
+               renderTagCheckbox ('taglist', $target_given_tags, $taginfo, $etype_by_pageno[$pageno]);
        echo '<tr><td class=tdleft>';
        printImageHREF ('SAVE', 'Save changes', TRUE);
        echo "</form></td><td class=tdright>";
@@ -4958,68 +4851,25 @@ function renderEntityTags ($entity_id = 0)
        finishPortlet();
 }
 
-function printTagTRs ($baseurl = '')
+function printTagTRs ($cell, $baseurl = '')
 {
-       global $expl_tags, $impl_tags, $auto_tags, $target_given_tags;
-       if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' and count ($target_given_tags))
+       if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' and count ($cell['etags']))
        {
-               echo "<tr><th width='50%' class=tagchain>Given explicit tags:</th><td class=tagchain>";
-               echo serializeTags ($target_given_tags, $baseurl) . "</td></tr>\n";
-               // only display "effective" line, when if differs
-               if (tagChainCmp ($target_given_tags, $expl_tags))
-                       echo "<tr><th width='50%' class=tagchain>Effective explicit tags:</th><td class=tagchain>" .
-                               serializeTags ($expl_tags, $baseurl) . "</td></tr>\n";
+               echo "<tr><th width='50%' class=tagchain>Explicit tags:</th><td class=tagchain>";
+               echo serializeTags ($cell['etags'], $baseurl) . "</td></tr>\n";
        }
-       if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' and count ($impl_tags))
+       if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' and count ($cell['itags']))
        {
-               echo "<tr><th width='50%' class=tagchain>Effective implicit tags:</th><td class=tagchain>";
-               echo serializeTags ($impl_tags, $baseurl) . "</td></tr>\n";
+               echo "<tr><th width='50%' class=tagchain>Implicit tags:</th><td class=tagchain>";
+               echo serializeTags ($cell['itags'], $baseurl) . "</td></tr>\n";
        }
-       if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' and count ($auto_tags))
+       if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' and count ($cell['atags']))
        {
                echo "<tr><th width='50%' class=tagchain>Automatic tags:</th><td class=tagchain>";
-               echo serializeTags ($auto_tags) . "</td></tr>\n";
+               echo serializeTags ($cell['atags']) . "</td></tr>\n";
        }
 }
 
-// Output a portlet with currently selected tags and prepare a form for update.
-function renderTagFilterPortlet ($tagfilter, $realm, $bypass_name = '', $bypass_value = '')
-{
-       global $pageno, $tabno, $taglist, $tagtree;
-       $objectivetags = getObjectiveTagTree ($tagtree, $realm);
-       startPortlet ('filter');
-       if (!count ($objectivetags))
-       {
-               echo "None used in current realm.<br>";
-               finishPortlet();
-               return;
-       }
-       echo '<table border=0 align=center>';
-
-       echo "<form method=get>\n";
-       echo "<input type=hidden name=page value=${pageno}>\n";
-       echo "<input type=hidden name=tab value=${tabno}>\n";
-       if ($bypass_name != '')
-               echo "<input type=hidden name=${bypass_name} value='${bypass_value}'>\n";
-       echo '<tr><td colspan=2>';
-       // Show a tree of tags, pre-select according to currently requested list filter.
-       foreach ($objectivetags as $taginfo)
-               renderTagCheckbox ('tagfilter', buildTagChainFromIds ($tagfilter), $taginfo);
-       echo '</td></tr><tr><td>';
-       printImageHREF ('apply', 'Apply filter', TRUE);
-       echo "</form></td><td>";
-
-       // "reset"
-       echo "<form method=get>\n";
-       echo "<input type=hidden name=page value=${pageno}>\n";
-       echo "<input type=hidden name=tab value=${tabno}>\n";
-       if ($bypass_name != '')
-               echo "<input type=hidden name=${bypass_name} value='${bypass_value}'>\n";
-       printImageHREF ('clear', 'reset', TRUE);
-       echo '</form></td></tr></table>';
-       finishPortlet();
-}
-
 // This one is going to replace the tag filter.
 function renderCellFilterPortlet ($preselect, $realm, $bypass_name = '', $bypass_value = '')
 {
@@ -5051,12 +4901,12 @@ function renderCellFilterPortlet ($preselect, $realm, $bypass_name = '', $bypass
                $hr = $ruler;
                // Show a tree of tags, pre-select according to currently requested list filter.
                global $tagtree;
-               $objectivetags = getObjectiveTagTree ($tagtree, $realm);
+               $objectivetags = getObjectiveTagTree ($tagtree, $realm, $preselect['tagidlist']);
                if (!count ($objectivetags))
                        echo "<tr><td colspan=2 class='tagbox sparenetwork'>(nothing is tagged yet)</td></tr>";
                else
                        foreach ($objectivetags as $taginfo)
-                               renderTagCheckbox ('cft', buildTagChainFromIds ($preselect['tagidlist']), $taginfo);
+                               renderTagCheckbox ('cft', buildTagChainFromIds ($preselect['tagidlist']), $taginfo, $realm);
        }
        // predicates block
        if (getConfigVar ('FILTER_SUGGEST_PREDICATES') == 'yes' or count ($preselect['pnamelist']))
@@ -5096,20 +4946,20 @@ function renderCellFilterPortlet ($preselect, $realm, $bypass_name = '', $bypass
                echo $hr;
                $hr = $ruler;
                // "apply"
-               echo '<tr><td>';
+               echo '<tr><td class=tdleft>';
                echo "<input type=hidden name=page value=${pageno}>\n";
                echo "<input type=hidden name=tab value=${tabno}>\n";
                if ($bypass_name != '')
                        echo "<input type=hidden name=${bypass_name} value='${bypass_value}'>\n";
-               printImageHREF ('apply', 'Apply filter', TRUE);
-               echo "</form></td><td>";
+               printImageHREF ('setfilter', 'set filter', TRUE);
+               echo "</form></td><td class=tdright>";
                // "reset"
                echo "<form method=get>\n";
                echo "<input type=hidden name=page value=${pageno}>\n";
                echo "<input type=hidden name=tab value=${tabno}>\n";
                if ($bypass_name != '')
                        echo "<input type=hidden name=${bypass_name} value='${bypass_value}'>\n";
-               printImageHREF ('clear', 'reset', TRUE);
+               printImageHREF ('resetfilter', 'reset filter', TRUE);
                echo '</form></td></tr>';
        }
        echo '</table>';
@@ -5117,7 +4967,7 @@ function renderCellFilterPortlet ($preselect, $realm, $bypass_name = '', $bypass
 }
 
 // Dump all tags in a single SELECT element.
-function renderNewEntityTags ()
+function renderNewEntityTags ($for_realm = '')
 {
        global $taglist, $tagtree;
        if (!count ($taglist))
@@ -5127,7 +4977,7 @@ function renderNewEntityTags ()
        }
        echo '<div class=tagselector><table border=0 align=center>';
        foreach ($tagtree as $taginfo)
-               renderTagCheckbox ('taglist', array(), $taginfo);
+               renderTagCheckbox ('taglist', array(), $taginfo, $for_realm);
        echo '</table></div>';
 }
 
@@ -5136,7 +4986,6 @@ function renderTagRollerForRow ($row_id)
        $a = rand (1, 20);
        $b = rand (1, 20);
        $sum = $a + $b;
-       showMessageOrError();
        printOpFormIntro ('rollTags', array ('realsum' => $sum));
        echo "<table border=1 align=center>";
        echo "<tr><td colspan=2>This special tool allows assigning tags to physical contents (racks <strong>and all contained objects</strong>) of the current ";
@@ -5153,9 +5002,7 @@ function renderTagRollerForRow ($row_id)
 function renderObjectSLB ($object_id)
 {
        global $nextorder;
-       showMessageOrError();
        // Keep the list in a variable to assist in decoding pool name below.
-       $rsplist = getIPv4RSPoolOptions();
 
        startPortlet ('Add new');
        echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
@@ -5163,7 +5010,7 @@ function renderObjectSLB ($object_id)
        echo "<tr valign=top><th>VS / RS pool</th><td class=tdleft>";
        printSelect (getIPv4VSOptions(), 'vs_id', NULL, 1);
        echo "</td><td>";
-       printSelect ($rsplist, 'pool_id', NULL, 2);
+       printSelect (getIPv4RSPoolOptions(), 'pool_id', NULL, 2);
        echo "</td><td>";
        printImageHREF ('add', 'Configure LB', TRUE, 5);
        echo "</td></tr>\n";
@@ -5186,9 +5033,9 @@ function renderObjectSLB ($object_id)
                        printImageHREF ('delete', 'Unconfigure');
                        echo "</a></td>";
                        echo "</td><td class=tdleft>";
-                       renderVSCell ($vs_id);
+                       renderCell (spotEntity ('ipv4vs', $vs_id));
                        echo "</td><td class=tdleft>";
-                       renderRSPoolCell ($vsinfo['pool_id'], $rsplist[$vsinfo['pool_id']]);
+                       renderCell (spotEntity ('ipv4rspool', $vsinfo['pool_id']));
                        echo "</td><td><textarea name=vsconfig>${vsinfo['vsconfig']}</textarea></td>";
                        echo "<td><textarea name=rsconfig>${vsinfo['rsconfig']}</textarea></td><td>";
                        printImageHREF ('SAVE', 'Save changes', TRUE);
@@ -5202,8 +5049,7 @@ function renderObjectSLB ($object_id)
 
 function renderEditRSPool ($pool_id)
 {
-       showMessageOrError();
-       $poolinfo = getRSPoolInfo ($pool_id);
+       $poolinfo = spotEntity ('ipv4rspool', $pool_id);
        printOpFormIntro ('updIPv4RSP');
        echo '<table border=0 align=center>';
        echo "<tr><th class=tdright>name:</th><td class=tdleft><input type=text name=name value='${poolinfo['name']}'></td></tr>\n";
@@ -5217,8 +5063,8 @@ function renderEditRSPool ($pool_id)
 
 function renderEditVService ($vsid)
 {
-       showMessageOrError();
-       $vsinfo = getVServiceInfo ($vsid);
+       $vsinfo = spotEntity ('ipv4vs', $vsid);
+       amplifyCell ($vsinfo);
        printOpFormIntro ('updIPv4VS');
        echo '<table border=0 align=center>';
        echo "<tr><th class=tdright>VIP:</th><td class=tdleft><input tabindex=1 type=text name=vip value='${vsinfo['vip']}'></td></tr>\n";
@@ -5258,7 +5104,6 @@ function renderRackCodeViewer ()
 function renderRackCodeEditor ()
 {
        $text = loadScript ('RackCode');
-       showMessageOrError();
        printOpFormIntro ('saveRackCode');
        echo <<<ENDJAVASCRIPT
 <script type="text/javascript">
@@ -5320,34 +5165,13 @@ ENDJAVASCRIPT;
 
 function renderUser ($user_id)
 {
-       global $target_given_tags;
-       $userinfo = getUserInfo ($user_id);
+       $userinfo = spotEntity ('user', $user_id);
 
        startPortlet ('summary');
        echo '<table border=0 align=center>';
        echo "<tr><th class=tdright>Account name:</th><td class=tdleft>${userinfo['user_name']}</td></tr>";
        echo '<tr><th class=tdright>Real name:</th><td class=tdleft>' . $userinfo['user_realname'] . '</td></tr>';
-       // Using printTagTRs() is inappropriate here, because autotags will be filled with current user's
-       // data, not the viewed one. Another special reason is that the displayed user's given tags are in
-       // the "target" chain.
-       $baseurl = makeHref(array('page'=>'userlist', 'tab'=>'default'))."&";
-       if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' and count ($target_given_tags))
-       {
-               echo "<tr><th width='50%' class=tagchain>Given explicit tags:</th><td class=tagchain>";
-               echo serializeTags ($target_given_tags, $baseurl) . "</td></tr>\n";
-       }
-       $target_shadow = getImplicitTags ($target_given_tags);
-       if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' and count ($target_shadow))
-       {
-               echo "<tr><th width='50%' class=tagchain>Given implicit tags:</th><td class=tagchain>";
-               echo serializeTags ($target_shadow, $baseurl) . "</td></tr>\n";
-       }
-       $target_auto_tags = generateEntityAutoTags ('user', $userinfo['user_name']);
-       if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' and count ($target_auto_tags))
-       {
-               echo "<tr><th width='50%' class=tagchain>Automatic tags:</th><td class=tagchain>";
-               echo serializeTags ($target_auto_tags) . "</td></tr>\n";
-       }
+       printTagTRs ($userinfo, makeHref(array('page'=>'userlist', 'tab'=>'default'))."&");
        echo '</table>';
        finishPortlet();
 
@@ -5356,7 +5180,6 @@ function renderUser ($user_id)
 
 function renderMyPasswordEditor ()
 {
-       showMessageOrError();
        printOpFormIntro ('changeMyPassword');
        echo '<table border=0 align=center>';
        echo "<tr><th class=tdright>Current password (*):</th><td><input type=password name=oldpassword tabindex=1></td></tr>";
@@ -5414,18 +5237,13 @@ function renderMyAccount ()
 }
 
 // File-related functions
-function renderFile ($file_id = 0)
+function renderFile ($file_id)
 {
        global $nextorder, $aac, $root;
-       if ($file_id <= 0)
-       {
-               showError ('Invalid file_id', __FUNCTION__);
-               return;
-       }
-       $file = getFileInfo ($file_id);
+       $file = spotEntity ('file', $file_id);
        if ($file == NULL)
        {
-               showError ('getFileInfo() failed', __FUNCTION__);
+               showError ('Error loading data', __FUNCTION__);
                return;
        }
        echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
@@ -5446,8 +5264,8 @@ function renderFile ($file_id = 0)
        echo "<tr><th width='50%' class=tdright>Accessed:</th>";
        printf("<td class=tdleft>%s</td></tr>", formatTimestamp($file['atime']));
 
-       printTagTRs (makeHref(array('page'=>'files', 'tab'=>'default'))."&");
-       if (!empty ($file['comment']))
+       printTagTRs ($file, makeHref(array('page'=>'files', 'tab'=>'default'))."&");
+       if (strlen ($file['comment']))
        {
                echo '<tr><th class=slbconf>Comment:</th><td>&nbsp;</td></tr>';
                echo '<tr><td colspan=2 class="dashed slbconf">' . string_insert_hrefs (htmlspecialchars ($file['comment'])) . '</td></tr>';
@@ -5466,13 +5284,11 @@ function renderFile ($file_id = 0)
                        switch ($link['entity_type'])
                        {
                                case 'user':
-                                       if (NULL === ($userinfo = getUserInfo ($link['entity_id'])))
-                                               echo "Internal error: user id ${link['entity_id']} not found";
-                                       else
-                                               renderCell ($userinfo);
-                                       break;
                                case 'ipv4net':
-                                       renderIPv4NetCell (getIPv4NetworkInfo ($link['entity_id']));
+                               case 'rack':
+                               case 'ipv4vs':
+                               case 'ipv4rspool':
+                                       renderCell (spotEntity ($link['entity_type'], $link['entity_id']));
                                        break;
                                default:
                                        echo formatEntityName ($link['entity_type']) . ': ';
@@ -5500,7 +5316,6 @@ function renderFile ($file_id = 0)
 
 function renderFileReuploader ()
 {
-       showMessageOrError();
        startPortlet ('Replace existing contents');
        printOpFormIntro ('replaceFile', array (), TRUE);
        echo "<input type=file size=10 name=file tabindex=100>&nbsp;\n";
@@ -5509,15 +5324,14 @@ function renderFileReuploader ()
        finishPortlet();
 }
 
-function renderFileProperties ($file_id = 0)
+function renderFileProperties ($file_id)
 {
-       $file = getFileInfo ($file_id);
+       $file = spotEntity ('file', $file_id);
        if ($file === NULL)
        {
-               showError ('getFileInfo() failed', __FUNCTION__);
+               showError ('Error loading data', __FUNCTION__);
                return;
        }
-       showMessageOrError();
        echo '<table border=0 align=center>';
        printOpFormIntro ('updateFile');
        echo "<tr><th class=tdright>MIME-type:</th><td class=tdleft><input tabindex=101 type=text name=file_type value='";
@@ -5540,8 +5354,6 @@ function renderFileBrowser ()
 function renderFileManager ()
 {
        global $nextorder;
-       showMessageOrError();
-
        // Used for uploading a parentless file
        startPortlet ('Upload new');
        echo "<table border=0 cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
@@ -5591,12 +5403,6 @@ function renderFileManager ()
 
 function renderFilesPortlet ($entity_type = NULL, $entity_id = 0)
 {
-       if ($entity_type == NULL || $entity_id <= 0)
-       {
-               showError ('Invalid entity info', __FUNCTION__);
-               return;
-       }
-
        $files = getFilesOfEntity ($entity_type, $entity_id);
        if (count ($files))
        {
@@ -5606,7 +5412,9 @@ function renderFilesPortlet ($entity_type = NULL, $entity_id = 0)
                foreach ($files as $file)
                {
                        echo "<tr valign=top><td class=tdleft>";
-                       renderFileCell ($file);
+                       // That's a bit of overkill and ought to be justified after
+                       // getFilesOfEntity() returns a standard cell list.
+                       renderCell (spotEntity ('file', $file['id']));
                        echo "</td><td class=tdleft>${file['comment']}</td></tr>";
                        if ('' != ($pcode = getFilePreviewCode ($file)))
                                echo "<tr><td colspan=2>${pcode}</td></tr>\n";
@@ -5616,16 +5424,9 @@ function renderFilesPortlet ($entity_type = NULL, $entity_id = 0)
        }
 }
 
-function renderFilesForEntity ($entity_id = 0)
+function renderFilesForEntity ($entity_id)
 {
        global $page, $pageno, $etype_by_pageno;
-       if ($entity_id <= 0)
-       {
-               showError ('Invalid entity info', __FUNCTION__);
-               return;
-       }
-
-       showMessageOrError();
        // Now derive entity_type and bypass_name from pageno.
        $entity_type = $etype_by_pageno[$pageno];
        $id_name = $page[$pageno]['bypass'];
@@ -5666,7 +5467,7 @@ function renderFilesForEntity ($entity_id = 0)
                foreach ($filelist as $file_id => $file)
                {
                        echo "<tr valign=top><td class=tdleft>";
-                       renderFileCell ($file);
+                       renderCell (spotEntity ('file', $file_id));
                        echo "</td><td class=tdleft>${file['comment']}</td><td class=tdcenter>";
                        echo "<a href='".makeHrefProcess(array('op'=>'unlinkFile', 'link_id'=>$file['link_id'], $id_name=>$entity_id))."'>";
                        printImageHREF ('CUT', 'Unlink file');
@@ -5700,7 +5501,7 @@ function printOpFormIntro ($opname, $extra = array(), $upload = FALSE)
 function niftyString ($string, $maxlen = 30)
 {
        $cutind = '&hellip;'; // length is 1
-       if (empty ($string))
+       if (!strlen ($string))
                return '&nbsp;';
        if (mb_strlen ($string) > $maxlen)
                return "<span title='" . htmlspecialchars ($string, ENT_QUOTES, 'UTF-8') . "'>" .
@@ -5723,7 +5524,7 @@ function printRoutersTD ($rlist)
        }
        echo "<td class='${rtrclass}'>";
        foreach ($rlist as $rtr)
-               renderRouterCell ($rtr['addr'], $rtr['iface'], $rtr['id'], $rtr['dname']);
+               renderRouterCell ($rtr['addr'], $rtr['iface'], spotEntity ('object', $rtr['id']));
        echo '</td>';
 }
 
@@ -5731,19 +5532,18 @@ function printRoutersTD ($rlist)
 function printIPv4NetInfoTDs ($netinfo, $tdclass = 'tdleft', $indent = 0, $symbol = 'spacer', $symbolurl = '')
 {
        global $root;
-       $tags = isset ($netinfo['id']) ? loadEntityTags ('ipv4net', $netinfo['id']) : array();
        if ($symbol == 'spacer')
        {
                $indent++;
                $symbol = '';
        }
        echo "<td class='${tdclass}' style='padding-left: " . ($indent * 16) . "px;'>";
-       if (!empty ($symbol))
+       if (strlen ($symbol))
        {
-               if (!empty ($symbolurl))
+               if (strlen ($symbolurl))
                        echo "<a href='${symbolurl}'>";
                printImageHREF ($symbol, $symbolurl);
-               if (!empty ($symbolurl))
+               if (strlen ($symbolurl))
                        echo '</a>';
        }
        if (isset ($netinfo['id']))
@@ -5757,44 +5557,107 @@ function printIPv4NetInfoTDs ($netinfo, $tdclass = 'tdleft', $indent = 0, $symbo
        else
        {
                echo niftyString ($netinfo['name']);
-               if (count ($tags))
-                       echo '<br><small>' . serializeTags ($tags, "${root}?page=ipv4space&tab=default&") . '</small>';
+               if (count ($netinfo['etags']))
+                       echo '<br><small>' . serializeTags ($netinfo['etags'], "${root}?page=ipv4space&tab=default&") . '</small>';
        }
        echo "</td>";
 }
 
-function renderIPv4NetCell ($netinfo)
-{
-       global $root;
-       echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
-       printImageHREF ('NET');
-       echo '</td>';
-       echo "<td><a href='${root}?page=ipv4net&id=${netinfo['id']}'>${netinfo['ip']}/${netinfo['mask']}</a></td></tr>";
-       if (strlen ($netinfo['name']))
-               echo "<tr><td><strong>" . niftyString ($netinfo['name']) . "</strong></td></tr>";
-       else
-               echo "<tr><td class=sparenetwork>no name</td></tr>";
-       echo '<td>';
-       $tags = loadEntityTags ('ipv4net', $netinfo['id']);
-       echo count ($tags) ? ("<small>" . serializeTags ($tags) . "</small>") : '&nbsp;';
-       echo "</td></tr></table>";
-}
-
 function renderCell ($cell)
 {
+       global $root;
        switch ($cell['realm'])
        {
        case 'user':
-               renderUserCell ($cell);
+               echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
+               printImageHREF ('USER');
+               echo '</td>';
+               echo "<td><a href='${root}?page=user&user_id=${cell['user_id']}'>${cell['user_name']}</a></td></tr>";
+               if (strlen ($cell['user_realname']))
+                       echo "<tr><td><strong>" . niftyString ($cell['user_realname']) . "</strong></td></tr>";
+               else
+                       echo "<tr><td class=sparenetwork>no name</td></tr>";
+               echo '<td>';
+               if (!isset ($cell['etags']))
+                       $cell['etags'] = loadEntityTags ('user', $cell['user_id']);
+               echo count ($cell['etags']) ? ("<small>" . serializeTags ($cell['etags']) . "</small>") : '&nbsp;';
+               echo "</td></tr></table>";
                break;
        case 'file':
-               renderFileCell ($cell);
+               echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
+               switch ($cell['type'])
+               {
+                       case 'text/plain':
+                               printImageHREF ('text file');
+                               break;
+                       case 'image/jpeg':
+                       case 'image/png':
+                       case 'image/gif':
+                               printImageHREF ('image file');
+                               break;
+                       default:
+                               printImageHREF ('empty file');
+                               break;
+               }
+               echo "</td><td>";
+               printf ("<a href='${root}?page=file&file_id=%s'><strong>%s</strong></a>", $cell['id'], niftyString ($cell['name']));
+               echo "</td><td rowspan=3 valign=top>";
+               if (isset ($cell['links']) and count ($cell['links']))
+                       printf ("<small>%s</small>", serializeFileLinks ($cell['links']));
+               echo "</td></tr><tr><td>";
+               echo count ($cell['etags']) ? ("<small>" . serializeTags ($cell['etags']) . "</small>") : '&nbsp;';
+               echo "</td></tr><tr><td><a href='${root}download.php?file_id=${cell['id']}'>";
+               printImageHREF ('download', 'Download file');
+               echo '</a>&nbsp;';
+               echo formatFileSize ($cell['size']);
+               echo "</td></tr></table>";
                break;
        case 'ipv4vs':
-               renderIPv4VSCell ($cell);
+               echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
+               printImageHREF ('VS');
+               echo "</td><td>";
+               echo "<a href='${root}?page=ipv4vs&vs_id=${cell['id']}'>";
+               echo $cell['dname'] . "</a></td></tr><tr><td>";
+               echo $cell['name'] . '</td></tr><tr><td>';
+               echo count ($cell['etags']) ? ("<small>" . serializeTags ($cell['etags']) . "</small>") : '&nbsp;';
+               echo "</td></tr></table>";
                break;
        case 'ipv4rspool':
-               renderRSPoolCell ($cell['id'], $cell['name']);
+               echo "<table class=slbcell><tr><td>";
+               echo "<a href='${root}?page=ipv4rspool&pool_id=${cell['id']}'>";
+               echo !strlen ($cell['name']) ? "ANONYMOUS pool [${cell['id']}]" : niftyString ($cell['name']);
+               echo "</a></td></tr><tr><td>";
+               printImageHREF ('RS pool');
+               echo "</td></tr><tr><td>";
+               echo count ($cell['etags']) ? ("<small>" . serializeTags ($cell['etags']) . "</small>") : '&nbsp;';
+               echo "</td></tr></table>";
+               break;
+       case 'ipv4net':
+               echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
+               printImageHREF ('NET');
+               echo '</td>';
+               echo "<td><a href='${root}?page=ipv4net&id=${cell['id']}'>${cell['ip']}/${cell['mask']}</a></td></tr>";
+               if (strlen ($cell['name']))
+                       echo "<tr><td><strong>" . niftyString ($cell['name']) . "</strong></td></tr>";
+               else
+                       echo "<tr><td class=sparenetwork>no name</td></tr>";
+               echo '<td>';
+               echo count ($cell['etags']) ? ("<small>" . serializeTags ($cell['etags']) . "</small>") : '&nbsp;';
+               echo "</td></tr></table>";
+               break;
+       case 'rack':
+               echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
+               $thumbwidth = getRackImageWidth();
+               $thumbheight = getRackImageHeight ($cell['height']);
+               echo "<img border=0 width=${thumbwidth} height=${thumbheight} title='${cell['height']} units' ";
+               echo "src='render_image.php?img=minirack&rack_id=${cell['id']}'>";
+               echo "</td><td>";
+               printf ("<a href='${root}?page=rack&rack_id=%s'><strong>%s</strong></a>", $cell['id'], niftyString ($cell['name']));
+               echo "</td></tr><tr><td>";
+               echo niftyString ($cell['comment']);
+               echo "</td></tr><tr><td>";
+               echo count ($cell['etags']) ? ("<small>" . serializeTags ($cell['etags']) . "</small>") : '&nbsp;';
+               echo "</td></tr></table>";
                break;
        default:
                showError ('odd data', __FUNCTION__);
@@ -5802,120 +5665,33 @@ function renderCell ($cell)
        }
 }
 
-function renderUserCell ($account)
-{
-       global $root;
-       echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
-       printImageHREF ('USER');
-       echo '</td>';
-       echo "<td><a href='${root}?page=user&user_id=${account['user_id']}'>${account['user_name']}</a></td></tr>";
-       if (strlen ($account['user_realname']))
-               echo "<tr><td><strong>" . niftyString ($account['user_realname']) . "</strong></td></tr>";
-       else
-               echo "<tr><td class=sparenetwork>no name</td></tr>";
-       echo '<td>';
-       if (!isset ($account['etags']))
-               $account['etags'] = loadEntityTags ('user', $account['user_id']);
-       echo count ($account['etags']) ? ("<small>" . serializeTags ($account['etags']) . "</small>") : '&nbsp;';
-       echo "</td></tr></table>";
-}
-
 function renderLBCell ($object_id)
 {
        global $root;
-       $oi = getObjectInfo ($object_id);
+       $oi = spotEntity ('object', $object_id);
        echo "<table class=slbcell><tr><td>";
        echo "<a href='${root}?page=object&object_id=${object_id}'>${oi['dname']}</a>";
        echo "</td></tr><tr><td>";
        printImageHREF ('LB');
-       echo "</td></tr><tr><td><small>";
-       echo serializeTags (loadEntityTags ('object', $object_id));
-       echo "</small></td></tr></table>";
-}
-
-function renderRSPoolCell ($pool_id, $pool_name)
-{
-       global $root;
-       echo "<table class=slbcell><tr><td>";
-       echo "<a href='${root}?page=ipv4rspool&pool_id=${pool_id}'>";
-       echo empty ($pool_name) ? "ANONYMOUS pool [${pool_id}]" : niftyString ($pool_name);
-       echo "</a></td></tr><tr><td>";
-       printImageHREF ('RS pool');
-       echo "</td></tr><tr><td><small>";
-       echo serializeTags (loadEntityTags ('ipv4rspool', $pool_id));
-       echo "</small></td></tr></table>";
-}
-
-// FIXME: migrate to renderIPv4VSCell()
-function renderVSCell ($vs_id)
-{
-       renderIPv4VSCell (getVServiceInfo ($vs_id));
-}
-
-function renderIPv4VSCell ($vsinfo)
-{
-       global $root;
-       echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
-       printImageHREF ('VS');
-       echo "</td><td>";
-       echo "<a href='${root}?page=ipv4vs&vs_id=${vsinfo['id']}'>";
-       // FIXME: this is a workaround
-       if (!isset ($vsinfo['dname']))
-               $vsinfo['dname'] = buildVServiceName ($vsinfo);
-       echo $vsinfo['dname'] . "</a></td></tr><tr><td>";
-       echo $vsinfo['name'];
-       echo '</td></tr><tr><td>';
-       $tags = loadEntityTags ('ipv4vs', $vsinfo['id']);
-       echo count ($tags) ? ("<small>" . serializeTags ($tags) . "</small>") : '&nbsp;';
+       echo "</td></tr><tr><td>";
+       if (count ($oi['etags']))
+               echo '<small>' . serializeTags ($oi['etags']) . '</small>';
        echo "</td></tr></table>";
 }
 
-function renderRouterCell ($dottedquad, $ifname, $object_id, $object_dname)
+function renderRouterCell ($dottedquad, $ifname, $cell)
 {
        global $root;
        echo "<table class=slbcell><tr><td rowspan=3>${dottedquad}";
-       if (!empty ($ifname))
+       if (strlen ($ifname))
                echo '@' . $ifname;
        echo "</td>";
-       echo "<td><a href='${root}?page=object&object_id=${object_id}&hl_ipv4_addr=${dottedquad}'><strong>${object_dname}</strong></a></td>";
+       echo "<td><a href='${root}?page=object&object_id=${cell['id']}&hl_ipv4_addr=${dottedquad}'><strong>${cell['dname']}</strong></a></td>";
        echo "</td></tr><tr><td>";
        printImageHREF ('router');
-       echo "</td></tr><tr><td><small>";
-       echo serializeTags (loadEntityTags ('object', $object_id));
-       echo "</small></td></tr></table>";
-}
-
-function renderFileCell ($fileinfo)
-{
-       global $root;
-       echo "<table class='slbcell vscell'><tr><td rowspan=3 width='5%'>";
-       switch ($fileinfo['type'])
-       {
-               case 'text/plain':
-                       printImageHREF ('text file');
-                       break;
-               case 'image/jpeg':
-               case 'image/png':
-               case 'image/gif':
-                       printImageHREF ('image file');
-                       break;
-               default:
-                       printImageHREF ('empty file');
-                       break;
-       }
-       echo "</td><td>";
-       printf ("<a href='${root}?page=file&file_id=%s'><strong>%s</strong></a>", $fileinfo['id'], niftyString ($fileinfo['name']));
-       echo "</td><td rowspan=3 valign=top>";
-       if (isset ($fileinfo['links']) and count ($fileinfo['links']))
-               printf ("<small>%s</small>", serializeFileLinks ($fileinfo['links']));
        echo "</td></tr><tr><td>";
-       if (!isset ($fileinfo['etags']))
-               $fileinfo['etags'] = loadEntityTags ('file', $fileinfo['id']);
-       echo count ($fileinfo['etags']) ? ("<small>" . serializeTags ($fileinfo['etags']) . "</small>") : '&nbsp;';
-       echo "</td></tr><tr><td><a href='${root}download.php?file_id=${fileinfo['id']}'>";
-       printImageHREF ('download', 'Download file');
-       echo '</a>&nbsp;';
-       echo formatFileSize ($fileinfo['size']);
+       if (count ($cell['etags']))
+               echo '<small>' . serializeTags ($cell['etags']) . '</small>';
        echo "</td></tr></table>";
 }
 
@@ -5969,7 +5745,6 @@ function getFilePreviewCode ($file)
 function renderTextEditor ($file_id)
 {
        global $CodePressMap;
-       showMessageOrError();
        $fullInfo = getFile ($file_id);
        printOpFormIntro ('updateFileText', array ('mtime_copy' => $fullInfo['mtime']));
        preg_match('/.+\.([^.]*)$/', $fullInfo['name'], $matches); # get file extension
@@ -6043,7 +5818,7 @@ function getTitle ($pageno)
 
 function showTabs ($pageno, $tabno)
 {
-       global $tab, $root, $page, $trigger, $tabextraclass;
+       global $tab, $root, $page, $trigger;
        if (!isset ($tab[$pageno]['default']))
                return;
        echo "<td><div class=greynavbar><ul id=foldertab style='margin-bottom: 0px; padding-top: 10px;'>";
@@ -6053,15 +5828,13 @@ function showTabs ($pageno, $tabno)
                if (!permitted ($pageno, $tabidx))
                        continue;
                // Dynamic tabs should only be shown in certain cases (trigger exists and returns true).
-               if (isset ($trigger[$pageno][$tabidx]))
-               {
-                       $ok = $trigger[$pageno][$tabidx] ();
-                       if (!$ok)
-                               continue;
-               }
-               $class = ($tabidx == $tabno) ? 'current' : 'std';
-               $extra = (isset ($tabextraclass[$pageno][$tabidx])) ? $tabextraclass[$pageno][$tabidx] : '';
-               echo "<li><a class=${class}{$extra}";
+               if (!isset ($trigger[$pageno][$tabidx]))
+                       $tabclass = 'std';
+               elseif (!strlen ($tabclass = $trigger[$pageno][$tabidx] ()))
+                       continue;
+               if ($tabidx == $tabno)
+                      $tabclass = 'current'; // override any class for an an active selection
+               echo "<li><a class=${tabclass}";
                echo " href='${root}?page=${pageno}&tab=${tabidx}";
                if (isset ($page[$pageno]['bypass']) and isset ($_REQUEST[$page[$pageno]['bypass']]))
                {
@@ -6092,7 +5865,7 @@ function dynamic_title_decoder ($path_position)
                assertUIntArg ('chapter_no', __FUNCTION__);
                $chapters = getChapterList();
                $chapter_no = $_REQUEST['chapter_no'];
-               $chapter_name = isset ($chapters[$chapter_no]) ? $chapters[$chapter_no] : 'N/A';
+               $chapter_name = isset ($chapters[$chapter_no]) ? $chapters[$chapter_no]['name'] : 'N/A';
                return array
                (
                        'name' => "Chapter '${chapter_name}'",
@@ -6100,7 +5873,7 @@ function dynamic_title_decoder ($path_position)
                );
        case 'user':
                assertUIntArg ('user_id', __FUNCTION__);
-               $userinfo = getUserInfo ($_REQUEST['user_id']);
+               $userinfo = spotEntity ('user', $_REQUEST['user_id']);
                return array
                (
                        'name' => "Local user '" . $userinfo['user_name'] . "'",
@@ -6108,22 +5881,23 @@ function dynamic_title_decoder ($path_position)
                );
        case 'ipv4rspool':
                assertUIntArg ('pool_id', __FUNCTION__);
-               $poolInfo = getRSPoolInfo ($_REQUEST['pool_id']);
+               $poolInfo = spotEntity ('ipv4rspool', $_REQUEST['pool_id']);
                return array
                (
-                       'name' => empty ($poolInfo['name']) ? 'ANONYMOUS' : $poolInfo['name'],
+                       'name' => !strlen ($poolInfo['name']) ? 'ANONYMOUS' : $poolInfo['name'],
                        'params' => array ('pool_id' => $_REQUEST['pool_id'])
                );
        case 'ipv4vs':
                assertUIntArg ('vs_id', __FUNCTION__);
+               $tmp = spotEntity ('ipv4vs', $_REQUEST['vs_id']);
                return array
                (
-                       'name' => buildVServiceName (getVServiceInfo ($_REQUEST['vs_id'])),
+                       'name' => $tmp['dname'],
                        'params' => array ('vs_id' => $_REQUEST['vs_id'])
                );
        case 'object':
                assertUIntArg ('object_id', __FUNCTION__);
-               $object = getObjectInfo ($_REQUEST['object_id']);
+               $object = spotEntity ('object', $_REQUEST['object_id']);
                if ($object == NULL)
                        return array
                        (
@@ -6137,7 +5911,7 @@ function dynamic_title_decoder ($path_position)
                );
        case 'rack':
                assertUIntArg ('rack_id', __FUNCTION__);
-               $rack = getRackData ($_REQUEST['rack_id']);
+               $rack = spotEntity ('rack', $_REQUEST['rack_id']);
                return array
                (
                        'name' => $rack['name'],
@@ -6158,7 +5932,7 @@ function dynamic_title_decoder ($path_position)
                        );
        case 'file':
                assertUIntArg ('file_id', __FUNCTION__);
-               $file = getFileInfo ($_REQUEST['file_id']);
+               $file = spotEntity ('file', $_REQUEST['file_id']);
                if ($file == NULL)
                        return array
                        (
@@ -6183,7 +5957,7 @@ function dynamic_title_decoder ($path_position)
                {
                case 'ipv4net':
                        assertUIntArg ('id', __FUNCTION__);
-                       $range = getIPv4NetworkInfo ($_REQUEST['id']);
+                       $range = spotEntity ('ipv4net', $_REQUEST['id']);
                        return array
                        (
                                'name' => $range['ip'] . '/' . $range['mask'],
@@ -6191,7 +5965,7 @@ function dynamic_title_decoder ($path_position)
                        );
                case 'ipaddress':
                        assertIPv4Arg ('ip', __FUNCTION__);
-                       $range = getIPv4NetworkInfo (getIPv4AddressNetworkId ($_REQUEST['ip']));
+                       $range = spotEntity ('ipv4net', getIPv4AddressNetworkId ($_REQUEST['ip']));
                        return array
                        (
                                'name' => $range['ip'] . '/' . $range['mask'],
@@ -6214,10 +5988,10 @@ function dynamic_title_decoder ($path_position)
                {
                case 'rack':
                        assertUIntArg ('rack_id', __FUNCTION__);
-                       $rack = getRackData ($_REQUEST['rack_id']);
+                       $rack = spotEntity ('rack', $_REQUEST['rack_id']);
                        if ($rack == NULL)
                        {
-                               showError ('getRackData() failed', __FUNCTION__);
+                               showError ('Rack not found', __FUNCTION__);
                                return NULL;
                        }
                        return array
@@ -6254,4 +6028,62 @@ function dynamic_title_decoder ($path_position)
        }
 }
 
+function dumpArray($arr)
+{
+       echo '<table class="exceptionParametersDump">';
+       foreach($arr as $key=>$value)
+       {
+               echo "<tr><th>$key</th><td>$value</td></tr>";
+       }
+       echo '</table>';
+}
+
+function print404($e)
+{
+       header("HTTP/1.1 404 Not Found");
+       echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
+       echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
+       echo "<head><title> Exception </title>\n";
+       echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
+       echo "<link rel=stylesheet type='text/css' href=pi.css />\n";
+       echo "<link rel=icon href='" . getFaviconURL() . "' type='image/x-icon' />";
+       echo '</head> <body>';
+       echo '<h2>Object: '.$e->getEntity().'#'.$e->getId().' not found</h2>';
+       echo '</body></html>';
+
+}
+
+function printGenericException($e)
+{
+       header("HTTP/1.1 500 Internal Server Error");
+       echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
+       echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
+       echo "<head><title> Exception </title>\n";
+       echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
+       echo "<link rel=stylesheet type='text/css' href=pi.css />\n";
+       echo "<link rel=icon href='" . getFaviconURL() . "' type='image/x-icon' />";
+       echo '</head> <body>';
+       echo '<h2>Uncaught exception: '.get_class($e).'</h2><code>'.$e->getMessage().'</code> (<code>'.$e->getCode().'</code>)';
+       echo '<p>at file <code>'.$e->getFile().'</code>, line <code>'.$e->getLine().'</code></p><pre>';
+       print_r($e->getTrace());
+       echo '</pre>';
+       echo '<h2>Parameters:</h2>';
+       echo '<h3>GET</h3>';
+       dumpArray($_GET);
+       echo '<h3>POST</h3>';
+       dumpArray($_POST);
+       echo '<h3>COOKIE</h3>';
+       dumpArray($_COOKIE);
+       echo '</body></html>';
+
+}
+
+function printException($e)
+{
+       if (get_class($e) == 'EntityNotFoundException')
+               print404($e);
+       else
+               printGenericException($e);
+}
+
 ?>