Index: branches/eli_branch/lib/ACL.inc.php
===================================================================
--- branches/eli_branch/lib/ACL.inc.php	(revision 451)
+++ branches/eli_branch/lib/ACL.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -23,10 +23,10 @@
 /*
 * ACL.inc.php
-* 
+*
 * Uses the ARO/ACO/AXO model of Access Control Lists.
 * Uses Modified Preorder Tree Traversal to maintain a tree-structure.
 * See: http://www.sitepoint.com/print/hierarchical-data-database
 * Includes a command-line tool for managing rights (codebase/bin/acl.cli.php).
-* 
+*
 *
 * @author   Quinn Comendant <quinn@strangecode.com>
@@ -41,5 +41,5 @@
     // Configuration parameters for this object.
     private $_params = array(
-        
+
         // If false nothing will be cached or retrieved. Useful for testing realtime data requests.
         'enable_cache' => true,
@@ -94,5 +94,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($params) && is_array($params)) {
             // Merge new parameters with old overriding only those passed.
@@ -113,5 +113,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($this->_params[$param])) {
             return $this->_params[$param];
@@ -145,5 +145,5 @@
                 $app->logMsg(sprintf('Dropping and recreating tables acl_tbl, aro_tbl, aco_tbl, axo_tbl.', null), LOG_INFO, __FILE__, __LINE__);
             }
-            
+
             // acl_tbl
             $db->query("
@@ -171,6 +171,6 @@
                 $qid = $db->query("SELECT 1 FROM acl_tbl");
                 if (mysql_num_rows($qid) == 0) {
-                    $qid = $db->query("REPLACE INTO acl_tbl VALUES ('1', '1', '1', 'deny', NOW())");                    
-                }                
+                    $qid = $db->query("REPLACE INTO acl_tbl VALUES ('1', '1', '1', 'deny', NOW())");
+                }
             }
 
@@ -202,6 +202,6 @@
                     $qid = $db->query("SELECT 1 FROM {$a_o}_tbl WHERE name = 'root'");
                     if (mysql_num_rows($qid) == 0) {
-                        $qid = $db->query("REPLACE INTO {$a_o}_tbl (name, lft, rgt, added_datetime) VALUES ('root', 1, 2, NOW())");                    
-                    }                    
+                        $qid = $db->query("REPLACE INTO {$a_o}_tbl (name, lft, rgt, added_datetime) VALUES ('root', 1, 2, NOW())");
+                    }
                 }
 
@@ -228,7 +228,7 @@
         $app =& App::getInstance();
         $db =& DB::getInstance();
-        
+
         $this->initDB();
-        
+
         switch ($type) {
         case 'aro' :
@@ -246,10 +246,10 @@
             break;
         }
-        
+
         // If $parent is null, use root object.
         if (is_null($parent)) {
             $parent = 'root';
         }
-        
+
         // Ensure node and parent name aren't empty.
         if ('' == trim($name) || '' == trim($parent)) {
@@ -257,5 +257,5 @@
             return false;
         }
-        
+
         // Ensure node is unique.
         $qid = $db->query("SELECT 1 FROM $tbl WHERE name = '" . $db->escapeString($name) . "'");
@@ -264,5 +264,5 @@
             return false;
         }
-        
+
         // Select the rgt of $parent.
         $qid = $db->query("SELECT rgt FROM $tbl WHERE name = '" . $db->escapeString($parent) . "'");
@@ -275,8 +275,8 @@
         $db->query("UPDATE $tbl SET lft = lft + 2 WHERE lft >= $parent_rgt");
         $db->query("UPDATE $tbl SET rgt = rgt + 2 WHERE rgt >= $parent_rgt");
-        
+
         // Insert new node just below parent. Lft is parent's old rgt.
         $db->query("
-            INSERT INTO $tbl (name, lft, rgt, added_datetime) 
+            INSERT INTO $tbl (name, lft, rgt, added_datetime)
             VALUES ('" . $db->escapeString($name) . "', $parent_rgt, $parent_rgt + 1, NOW())
         ");
@@ -315,5 +315,5 @@
         $app =& App::getInstance();
         $db =& DB::getInstance();
-        
+
         $this->initDB();
 
@@ -336,5 +336,5 @@
             break;
         }
-        
+
         // Ensure node name isn't empty.
         if ('' == trim($name)) {
@@ -342,5 +342,5 @@
             return false;
         }
-        
+
         // Select the lft and rgt of $name to use for selecting children and reordering transversals.
         $qid = $db->query("SELECT lft, rgt FROM $tbl WHERE name = '" . $db->escapeString($name) . "'");
@@ -349,8 +349,8 @@
             return false;
         }
-        
+
         // Remove node and all children of node, as well as acl_tbl links.
         $db->query("
-            DELETE $tbl, acl_tbl 
+            DELETE $tbl, acl_tbl
             FROM $tbl
             LEFT JOIN acl_tbl ON ($tbl.$primary_key = acl_tbl.$primary_key)
@@ -366,5 +366,5 @@
         return true;
     }
-    
+
     // Alias functions for the different object types.
     public function removeRequestObject($name)
@@ -397,5 +397,5 @@
         $app =& App::getInstance();
         $db =& DB::getInstance();
-        
+
         $this->initDB();
 
@@ -418,10 +418,10 @@
             break;
         }
-        
+
         // If $new_parent is null, use root object.
         if (is_null($new_parent)) {
             $new_parent = 'root';
         }
-        
+
         // Ensure node and parent name aren't empty.
         if ('' == trim($name) || '' == trim($new_parent)) {
@@ -429,5 +429,5 @@
             return false;
         }
-        
+
         // Select the lft and rgt of $name to use for selecting children and reordering transversals.
         $qid = $db->query("SELECT lft, rgt FROM $tbl WHERE name = '" . $db->escapeString($name) . "'");
@@ -436,5 +436,5 @@
             return false;
         }
-        
+
         // Total number of transversal values (that is, the count of self plus all children times two).
         $total_transversal_value = ($rgt - $lft + 1);
@@ -446,5 +446,5 @@
             return false;
         }
-        
+
         // Ensure the new parent is not a child of the node being moved.
         if ($new_parent_rgt <= $rgt && $new_parent_rgt >= $lft) {
@@ -452,5 +452,5 @@
             return false;
         }
-        
+
         // Collect unique ids of all nodes being moved. The transversal numbers will become duplicated so these will be needed to identify these.
         $qid = $db->query("
@@ -472,8 +472,8 @@
         // Apply transformation to new parent rgt also.
         $new_parent_rgt = $new_parent_rgt > $rgt ? $new_parent_rgt - $total_transversal_value : $new_parent_rgt;
-        
+
         // Update transversal values of moved node and children.
         $db->query("
-            UPDATE $tbl SET 
+            UPDATE $tbl SET
                 lft = lft - ($lft - $new_parent_rgt),
                 rgt = rgt - ($lft - $new_parent_rgt)
@@ -488,5 +488,5 @@
         return true;
     }
-    
+
     // Alias functions for the different object types.
     public function moveRequestObject($name, $new_parent=null)
@@ -502,5 +502,5 @@
         return $this->move($name, $new_parent, 'axo');
     }
-    
+
     /*
     * Add an entry to the acl_tbl to allow (or deny) a truple with the specified
@@ -528,5 +528,5 @@
         $aco = is_null($aco) ? 'root' : $aco;
         $axo = is_null($axo) ? 'root' : $axo;
-        
+
         // Flush old cached values.
         $cache_hash = $aro . '|' . $aco . '|' . $axo;
@@ -552,8 +552,8 @@
         // Access must be 'allow' or 'deny'.
         $allow = 'allow' == $access ? 'allow' : 'deny';
-        
+
         $db->query("REPLACE INTO acl_tbl VALUES ('$aro_id', '$aco_id', '$axo_id', '$allow', NOW())");
         $app->logMsg(sprintf('Set %s: %s -> %s -> %s.', $allow, $aro, $aco, $axo), LOG_INFO, __FILE__, __LINE__);
-        
+
         return true;
     }
@@ -577,5 +577,5 @@
         return $this->grant($aro, $aco, $axo, 'deny');
     }
-    
+
     /*
     * Delete an entry from the acl_tbl completely to allow other permissions to cascade down.
@@ -610,5 +610,5 @@
         $aco = is_null($aco) ? 'root' : $aco;
         $axo = is_null($axo) ? 'root' : $axo;
-        
+
         // Flush old cached values.
         $cache_hash = $aro . '|' . $aco . '|' . $axo;
@@ -621,5 +621,5 @@
             return false;
         }
-        
+
         $qid = $db->query("
             DELETE acl_tbl
@@ -632,11 +632,11 @@
 
         $app->logMsg(sprintf('Deleted %s acl_tbl links: %s -> %s -> %s', mysql_affected_rows($db->getDBH()), $aro, $aco, $axo), LOG_INFO, __FILE__, __LINE__);
-        
+
         return true;
     }
-    
+
     /*
     * Calculates the most specific cascading privilege found for a requested
-    * ARO -> ACO -> AXO entry. Returns FALSE if the entry is denied. By default, 
+    * ARO -> ACO -> AXO entry. Returns FALSE if the entry is denied. By default,
     * all entries are denied, unless some point in the hierarchy is set to "allow."
     *
@@ -654,5 +654,5 @@
         $app =& App::getInstance();
         $db =& DB::getInstance();
-        
+
         $this->initDB();
 
@@ -661,5 +661,5 @@
         $aco = is_null($aco) || '' == trim($aco) ? 'root' : $aco;
         $axo = is_null($axo) || '' == trim($axo) ? 'root' : $axo;
-        
+
         $cache_hash = $aro . '|' . $aco . '|' . $axo;
         if ($this->cache->exists($cache_hash) && true === $this->getParam('enable_cache')) {
@@ -687,5 +687,5 @@
             $this->cache->set($cache_hash, $access);
         }
-        
+
         if ('allow' == $access) {
             $app->logMsg(sprintf('Access granted: %s -> %s -> %s.', $aro, $aco, $axo), LOG_DEBUG, __FILE__, __LINE__);
@@ -697,5 +697,30 @@
     }
 
+    /*
+    * Bounce user if they are denied access. Because this function calls dieURL() it must be called before any other HTTP header output.
+    *
+    * @access   public
+    * @param    string $aro Identifier of an existing ARO object.
+    * @param    string $aco Identifier of an existing ACO object (or null to use root).
+    * @param    string $axo Identifier of an existing AXO object (or null to use root).
+    * @param    string $message The text description of a message to raise.
+    * @param    int    $type    The type of message: MSG_NOTICE,
+    *                           MSG_SUCCESS, MSG_WARNING, or MSG_ERR.
+    * @param    string $file    __FILE__.
+    * @param    string $line    __LINE__.
+    * @author   Quinn Comendant <quinn@strangecode.com>
+    * @version  1.0
+    * @since    20 Jan 2014 12:09:03
+    */
+    public function requireAllow($aro, $aco=null, $axo=null, $message='', $type=MSG_NOTICE, $file=null, $line=null)
+    {
+		$app =& App::getInstance();
+
+        if (!$this->check($aro, $aco, $axo)) {
+            $message = '' == trim($message) ? sprintf(_("You have insufficient privileges to view <em>%s %s</em>"), $aco, $axo) : $message;
+            $app->raiseMsg($message, $type, $file, $line);
+            $app->dieBoomerangURL();
+        }
+    }
+
 } // End class.
-
-
Index: branches/eli_branch/lib/App.inc.php
===================================================================
--- branches/eli_branch/lib/App.inc.php	(revision 451)
+++ branches/eli_branch/lib/App.inc.php	(revision 467)
@@ -403,6 +403,8 @@
             $this->db->close();
         }
+        $mem_current = memory_get_usage();
+        $mem_peak = memory_get_peak_usage();
         $this->timer->stop('_app');
-        $this->logMsg(sprintf('Script ended gracefully. Execution time: %s. Number of db queries: %s.', $this->timer->getTime('_app'), $num_queries), LOG_DEBUG, __FILE__, __LINE__);
+        $this->logMsg(sprintf('Script ended gracefully. Execution time: %s. Number of db queries: %s. Memory usage: %s. Peak memory: %s.', $this->timer->getTime('_app'), $num_queries, $mem_current, $mem_peak), LOG_DEBUG, __FILE__, __LINE__);
     }
 
@@ -961,7 +963,14 @@
             // urlencode is not used here, not for form data!
             $query_args = array_merge($this->_carry_queries, $one_time_carry_queries);
-            foreach ($query_args as $key=>$val) {
-                printf('<input type="hidden" name="%s" value="%s" />', $key, $val);
-            }
+            foreach ($query_args as $key => $val) {
+                if (is_array($val)) {
+                    foreach ($val as $subval) {
+                        printf('<input type="hidden" name="%s[]" value="%s" />', $key, $subval);
+                    }
+                } else {
+                    printf('<input type="hidden" name="%s" value="%s" />', $key, $val);
+                }
+            }
+            unset($query_args, $key, $val, $subval);
         }
 
@@ -1238,5 +1247,3 @@
         }
     }
-
-
 } // End.
Index: branches/eli_branch/lib/Auth_SQL.inc.php
===================================================================
--- branches/eli_branch/lib/Auth_SQL.inc.php	(revision 451)
+++ branches/eli_branch/lib/Auth_SQL.inc.php	(revision 467)
@@ -424,4 +424,9 @@
             // No login: failed authentication!
             return false;
+        }
+
+        // Convert 'priv' to 'user_type' nomenclature to support older implementations.
+        if (isset($user_data['priv'])) {
+            $user_data['user_type'] = $user_data['priv'];
         }
 
@@ -649,6 +654,4 @@
             }
             $app->logMsg(sprintf('User_id %s (%s) session expired: %s', $this->get('user_id'), $this->get('username'), join(', ', $expire_reasons)), LOG_INFO, __FILE__, __LINE__);
-        } else {
-            $app->logMsg(sprintf('Session not authenticated: %s', getDump($_SESSION['_auth_sql'][$this->_ns])), LOG_DEBUG, __FILE__, __LINE__);
         }
 
Index: branches/eli_branch/lib/Cache.inc.php
===================================================================
--- branches/eli_branch/lib/Cache.inc.php	(revision 451)
+++ branches/eli_branch/lib/Cache.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -31,5 +31,5 @@
  * @since   2001
  */
- 
+
 // Flags.
 define('CACHE_ALLOW_OVERSIZED', 1);
@@ -42,5 +42,5 @@
     // Configuration parameters for this object.
     private $_params = array(
-        
+
         // If false nothing will be cached or retrieved. Useful for testing realtime data requests.
         'enabled' => true,
@@ -48,12 +48,12 @@
         // The maximum size in bytes of any one variable.
         'item_size_limit' => 4194304, // 4 MB
-        
+
         // The maximum size in bytes before the cache will begin flushing out old items.
         'stack_size_limit' => 4194304, // 4 MB
-        
+
         // The minimum items to keep in the cache regardless of item or cache size.
         'min_items' => 5,
     );
-    
+
     /*
     * Constructor
@@ -68,5 +68,5 @@
     {
         $app =& App::getInstance();
-        
+
         $this->_ns = $namespace;
 
@@ -75,5 +75,5 @@
             $this->setParam(array('enabled' => false));
         }
-        
+
         if (!isset($_SESSION['_cache'][$this->_ns])) {
             $this->clear();
@@ -127,5 +127,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($this->_params[$param])) {
             return $this->_params[$param];
@@ -138,5 +138,5 @@
     /**
      * Stores a new variable in the session cache. The $key should not be numeric
-     * because the array_shift function will reset the key to the next largest 
+     * because the array_shift function will reset the key to the next largest
      * int key. Weird behavior I can't understand. For example $cache["123"] will become $cache[0]
      *
@@ -168,5 +168,5 @@
             $app->logMsg(sprintf('Serialized variable (%s bytes) more than stack_size_limit (%s bytes).', $var_len, $this->getParam('stack_size_limit')), LOG_NOTICE, __FILE__, __LINE__);
             return false;
-        }        
+        }
 
         // Remove any value already stored under this key.
@@ -253,5 +253,5 @@
         }
     }
-    
+
     /*
     * Delete all existing items from the cache.
Index: branches/eli_branch/lib/Email.inc.php
===================================================================
--- branches/eli_branch/lib/Email.inc.php	(revision 451)
+++ branches/eli_branch/lib/Email.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,24 +11,25 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/**
- * Email.inc.php
- *
- * Easy email template usage.
- *
- * @author  Quinn Comendant <quinn@strangecode.com>
- * @version 1.0
- * 
- 
-// Example.
+/*
+* Email.inc.php
+*
+* Easy email template usage.
+*
+* @author  Quinn Comendant <quinn@strangecode.com>
+* @version 1.0
+*
+* Example of use:
+---------------------------------------------------------------------
+// Setup email object.
 $email = new Email(array(
     'to' => array($frm['email'], 'q@lovemachine.local'),
@@ -49,7 +50,7 @@
     $app->logMsg(sprintf('Error sending confirmation email to address %s', $frm['email']), LOG_NOTICE, __FILE__, __LINE__);
 }
-
- * 
- */
+---------------------------------------------------------------------
+*/
+
 class Email {
 
@@ -61,9 +62,9 @@
         'headers' => null,
         'regex' => null,
-        
+
         // A single carriage return (\n) should terminate lines for locally injected mail.
         // A carriage return + line-feed (\r\n) should be used if sending mail directly with SMTP.
         'crlf' => "\n",
-        
+
         // RFC 2822 says line length MUST be no more than 998 characters, and SHOULD be no more than 78 characters, excluding the CRLF.
         // http://mailformat.dan.info/body/linelength.html
@@ -120,5 +121,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($params) && is_array($params)) {
             // Enforce valid email addresses.
@@ -147,5 +148,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($this->_params[$param])) {
             return $this->_params[$param];
@@ -167,5 +168,5 @@
     {
 		$app =& App::getInstance();
-    
+
         // Load file, using include_path.
         if (!$this->_template = file_get_contents($template, true)) {
@@ -191,5 +192,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if ('' == trim($string)) {
             $app->logMsg(sprintf('Empty string provided.', null), LOG_ERR, __FILE__, __LINE__);
@@ -215,5 +216,5 @@
     {
 		$app =& App::getInstance();
-    
+
         // Ensure template exists.
         if (!isset($this->_template)) {
@@ -285,5 +286,5 @@
         $final_body = isset($this->_template_replaced) ? $this->_template_replaced : $this->_template;
         if (false !== $this->getParam('wrap')) {
-            $final_body = wordwrap($final_body, $this->getParam('line_length'), $this->getParam('crlf'));            
+            $final_body = wordwrap($final_body, $this->getParam('line_length'), $this->getParam('crlf'));
         }
 
@@ -320,5 +321,5 @@
             $envelope_sender_header = sprintf('-f %s', $envelope_sender_address);
         } else {
-            $envelope_sender_header = '';            
+            $envelope_sender_header = '';
         }
 
@@ -331,5 +332,5 @@
         }
 
-        // Send email without 5th parameter if safemode is enabled. 
+        // Send email without 5th parameter if safemode is enabled.
         if (ini_get('safe_mode')) {
             $ret = mb_send_mail($final_to, $this->_params['subject'], $final_body, $final_headers);
@@ -337,5 +338,5 @@
             $ret = mb_send_mail($final_to, $this->_params['subject'], $final_body, $final_headers, $envelope_sender_header);
         }
-        
+
         // Ensure message was successfully accepted for delivery.
         if ($ret) {
@@ -345,5 +346,5 @@
             $app->logMsg(sprintf('Email failure with parameters: %s, %s, %s, %s', $final_to, $this->_params['subject'], str_replace("\r\n", '\r\n', $final_headers), $envelope_sender_header), LOG_NOTICE, __FILE__, __LINE__);
             return false;
-        } 
+        }
     }
 
@@ -366,5 +367,5 @@
     {
 		$app =& App::getInstance();
-    
+
         // If an array, check values recursively.
         if (is_array($email)) {
Index: branches/eli_branch/lib/FormValidator.inc.php
===================================================================
--- branches/eli_branch/lib/FormValidator.inc.php	(revision 451)
+++ branches/eli_branch/lib/FormValidator.inc.php	(revision 467)
@@ -481,5 +481,4 @@
             $app->logMsg(sprintf('The email address %s is not valid.', oTxt($email)), LOG_DEBUG, __FILE__, __LINE__);
             return false;
-            break;
 
         case parent::EMAIL_LENGTH_FAIL :
@@ -488,5 +487,4 @@
             $app->logMsg(sprintf('The email address %s must contain less than 256 characters.', oTxt($email)), LOG_DEBUG, __FILE__, __LINE__);
             return false;
-            break;
 
         case parent::EMAIL_MX_FAIL :
@@ -495,10 +493,8 @@
             $app->logMsg(sprintf('The email address %s does not have a valid domain name.', oTxt($email)), LOG_INFO, __FILE__, __LINE__);
             return false;
-            break;
 
         case parent::EMAIL_SUCCESS :
         default :
             return true;
-            break;
         }
     }
@@ -535,5 +531,5 @@
         $app =& App::getInstance();
 
-        if (parent::validateStrDate(getFormData($form_name))) {
+        if (parent::validateStrDate(getFormData($form_name, ''))) {
             return true;
         } else {
Index: branches/eli_branch/lib/Hierarchy.inc.php
===================================================================
--- branches/eli_branch/lib/Hierarchy.inc.php	(revision 451)
+++ branches/eli_branch/lib/Hierarchy.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -23,5 +23,5 @@
 /**
  * Hierarchy.inc.php
- * 
+ *
  * Objective: This class provides the tools to organize pieces of data into a
  * hierarchy of nodes. Any form of data (article, product, image) can be
@@ -116,5 +116,5 @@
     {
 			$app =& App::getInstance();
-	
+
             if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -150,5 +150,5 @@
     {
 			$app =& App::getInstance();
-	
+
             if (preg_match('/^([[:alnum:]]+)__-?([[:digit:]]+)$/', $node, $node_parts)) {
             return array('node_type' => $node_parts[1], 'node_id' => $node_parts[2]);
@@ -171,5 +171,5 @@
 		$app =& App::getInstance();
 		$db =& DB::getInstance();
-	
+
         if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -250,5 +250,5 @@
 		$app =& App::getInstance();
 		$db =& DB::getInstance();
-	
+
         if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -377,5 +377,5 @@
 		$app =& App::getInstance();
 		$db =& DB::getInstance();
-	
+
         if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -428,5 +428,5 @@
 		$app =& App::getInstance();
 		$db =& DB::getInstance();
-	
+
         if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -472,5 +472,5 @@
 		$app =& App::getInstance();
 		$db =& DB::getInstance();
-	
+
         if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -564,5 +564,5 @@
     {
 		$app =& App::getInstance();
-	
+
         if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -625,5 +625,5 @@
     {
 		$db =& DB::getInstance();
-	
+
         static $output = array();
         static $return_flag;
@@ -680,5 +680,5 @@
 		$app =& App::getInstance();
 		$db =& DB::getInstance();
-	
+
         if (!isset($child_type) || !isset($child_id)) {
             if ($this->node_init) {
@@ -731,5 +731,5 @@
     {
 		$app =& App::getInstance();
-	
+
         static $output = array();
         static $is_a_leaf = array();
@@ -804,5 +804,5 @@
     {
 		$db =& DB::getInstance();
-	
+
         // Reset all the category counters to zero.
         $db->query("UPDATE node_tbl SET subnode_quantity = 0");
@@ -828,5 +828,5 @@
     {
 		$db =& DB::getInstance();
-	
+
         $db->query("
             UPDATE node_tbl
Index: branches/eli_branch/lib/Image.inc.php
===================================================================
--- branches/eli_branch/lib/Image.inc.php	(revision 451)
+++ branches/eli_branch/lib/Image.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -49,11 +49,11 @@
             // Pattern passed to glob() with $id to match image filenames.
             'filename_pattern' => '%s*',
-            
+
             // The path to the image source directory. (Ex: /var/www/htdocs/images)
             'base_path' => '',
-            
+
             // The URL to the image directory. (Ex: /images)
             'base_url' => '',
-            
+
             // Image to use in the case of a missing image.
             'default_image_file' => '',
@@ -61,5 +61,5 @@
         $this->_params = array_merge($defaults, $params);
     }
-    
+
     /**
      * Tests if an image with specified id exists on the file system.
@@ -77,7 +77,8 @@
         $filepath = preg_match('!://!', $src) ? $src : getenv('DOCUMENT_ROOT') . $src;
         // Use exif_imagetype to check not only file existence but that of a valid image.
+        // The return value is the same value that getimagesize() returns in index 2 but exif_imagetype() is much faster.
         return false != @exif_imagetype($filepath);
     }
-    
+
     /**
      * Returns the value from getimagesize().
@@ -85,8 +86,8 @@
      * @access  public
      * @param   string  $id     Unique image identifier.
-     * @param   int     $key    Which element from the array returned by getimagesize: 
-     *                   - Index 0 contains the width of the image in pixels. 
-     *                   - Index 1 contains the height. 
-     *                   - Index 2 is the type of the image. 
+     * @param   int     $key    Which element from the array returned by getimagesize:
+     *                   - Index 0 contains the width of the image in pixels.
+     *                   - Index 1 contains the height.
+     *                   - Index 2 is the type of the image.
      *                   - Index 3 is height="yyy" width="xxx" string.
      * @return  mixed   return value of getimagesize.
@@ -102,5 +103,5 @@
         return isset($img_size[$key]) ? $img_size[$key] : false;
     }
-    
+
     /**
      * Returns the URL to the source of image specified by id.
@@ -126,5 +127,5 @@
 
     /**
-     * Returns an HTML <img> tag with the src set to an image specified by id.  
+     * Returns an HTML <img> tag with the src set to an image specified by id.
      * Automatically prints image width and height.
      *
@@ -142,5 +143,5 @@
         $src = $this->oSrc($id);
         $filepath = preg_match('!://!', $src) ? $src : getenv('DOCUMENT_ROOT') . $src;
-        
+
         if (false === ($gis = @getimagesize($filepath)) || preg_match('/width|height/', $extra)) {
             $image_size = '';
@@ -148,5 +149,5 @@
             $image_size = $gis[3];
         }
-        
+
         return sprintf('<img src="%s" %s alt="%s" %s />',
             $src,
Index: branches/eli_branch/lib/Navigation.inc.php
===================================================================
--- branches/eli_branch/lib/Navigation.inc.php	(revision 451)
+++ branches/eli_branch/lib/Navigation.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -28,5 +28,5 @@
  * and titles, as well as setting page params such as hiding the page title on
  * some pages but not others, and storing vars like the page title itself.
- * 
+ *
  * Note: this class was renamed from "Nav" because of the change in API and to be more descriptive.
  *
@@ -37,5 +37,5 @@
 
     // Configuration parameters for this object.
-    private $_params = array(        
+    private $_params = array(
         'head_title' => true,
         'body_title' => true,
@@ -68,5 +68,5 @@
      * current page added last. Vars can be specified for any page, but only vars
      * from the "current" page will be accessed with Nav::get.
-     * 
+     *
      * @access  public
      * @param   string  $title      The title of the page.
@@ -94,5 +94,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($params) && is_array($params)) {
             // Merge new parameters with old overriding only those passed.
@@ -113,5 +113,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($this->_params[$param])) {
             return $this->_params[$param];
@@ -142,5 +142,5 @@
     {
         // Set params of current page.
-        $curr_page =& $this->pages[sizeof($this->pages) - 1];        
+        $curr_page =& $this->pages[sizeof($this->pages) - 1];
         $curr_page[$key] = $val;
     }
@@ -157,5 +157,5 @@
     {
         $curr_page =& $this->pages[sizeof($this->pages) - 1];
-        
+
         switch ($key) {
         case 'title' :
@@ -279,9 +279,12 @@
      * @return  mixed   The value set for $return, TRUE by default.
      */
-    public function currentPage($page_uri, $return=true)
-    {
-        if (preg_match('/^' . preg_quote(urldecode($page_uri), '/') . '/i', $_SERVER['PHP_SELF'])) {
-            return $return;
-        }
+    public function currentPage($test_uri, $true_return=true, $false_return=false, $strip_query=false)
+    {
+        $actual_uri = $strip_query ? strtok($_SERVER['REQUEST_URI'], '?') : $_SERVER['REQUEST_URI'];
+        $test_uri = $strip_query ? strtok($test_uri, '?') : $test_uri;
+        if (preg_match('/^' . preg_quote(urldecode($test_uri), '/') . '$/i', $actual_uri)) {
+            return $true_return;
+        }
+        return $false_return;
     }
 
Index: branches/eli_branch/lib/PEdit.inc.php
===================================================================
--- branches/eli_branch/lib/PEdit.inc.php	(revision 451)
+++ branches/eli_branch/lib/PEdit.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -35,11 +35,11 @@
  * and call printing/editing functions where you want data and forms to
  * show up.
- * 
+ *
  * @author  Quinn Comendant <quinn@strangecode.com>
  * @concept Beau Smith <beau@beausmith.com>
- * @version 2.0 
- * 
+ * @version 2.0
+ *
  * Example of use:
- 
+
  // Initialize PEdit object.
  require_once 'codebase/lib/PEdit.inc.php';
@@ -48,16 +48,16 @@
      'authorized' => true,
  ));
- 
+
  // Setup content data types.
  $pedit->set('title');
  $pedit->set('content', array('type' => 'textarea'));
- 
+
  // After setting all parameters and data, load the data.
  $pedit->start();
- 
+
  // Print content.
  echo $pedit->get('title');
  echo $pedit->get('content');
- 
+
  // Print additional PEdit functionality.
  $pedit->formBegin();
@@ -96,9 +96,9 @@
     {
         $this->setParam($params);
-        
+
         if ($this->getParam('authorized') === true) {
             $this->_authorized = true;
         }
-        
+
         // Setup PEAR XML libraries.
         require_once 'XML/Serializer.php';
@@ -114,5 +114,5 @@
         ));
     }
-    
+
     /**
      * Set (or overwrite existing) parameters by passing an array of new parameters.
@@ -143,5 +143,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($this->_params[$param])) {
             return $this->_params[$param];
@@ -151,5 +151,5 @@
         }
     }
-    
+
     /*
     * Load the pedit data and run automatic functions.
@@ -166,9 +166,9 @@
             trigger_error(sprintf('PEdit data directory not found: %s', $this->getParam('data_dir')), E_USER_WARNING);
         }
-        
+
         // The location of the data file. (i.e.: "COMMON_DIR/html/_pedit_data/news/index.xml")
         $this->_data_file = sprintf('%s%s.xml', $this->getParam('data_dir'), $_SERVER['SCRIPT_NAME']);
-        
-        // Make certain the evaluated path matches the assumed path (realpath will expand /../../); 
+
+        // Make certain the evaluated path matches the assumed path (realpath will expand /../../);
         // if realpath returns FALSE we're not concerned because it means the file doesn't exist (_initializeDataFile() will create it).
         if (false !== realpath($this->_data_file) && $this->_data_file !== realpath($this->_data_file)) {
@@ -199,5 +199,5 @@
             break;
         }
-        
+
         // Load data.
         $this->_loadDataFile();
@@ -258,5 +258,5 @@
             return false;
         }
-        ?>        
+        ?>
         <form action="<?php echo oTxt($_SERVER['PHP_SELF']); ?>" method="post" id="sc-pedit-form">
         <input type="hidden" name="filename" value="<?php echo oTxt($_SERVER['PHP_SELF']); ?>" />
@@ -307,5 +307,5 @@
     public function printForm($name, $type='text')
     {
-        if ($this->_authorized && $this->op == 'Edit' && $this->_data_loaded) {        
+        if ($this->_authorized && $this->op == 'Edit' && $this->_data_loaded) {
             ?>
             <div class="sc-pedit-item">
@@ -468,5 +468,5 @@
         }
         $xml_file_contents = file_get_contents($this->_data_file);
-        $status = $this->xml_unserializer->unserialize($xml_file_contents, false);    
+        $status = $this->xml_unserializer->unserialize($xml_file_contents, false);
         if (PEAR::isError($status)) {
             $app->logMsg(sprintf('XML_Unserialize error: %s', $status->getMessage()), LOG_WARNING, __FILE__, __LINE__);
@@ -487,5 +487,5 @@
         return true;
     }
-    
+
     /*
     * Start a new data file.
@@ -535,5 +535,5 @@
                 return false;
             }
-            
+
             // Collect posted data that is already specified in _data (by set()).
             foreach ($new_data as $name => $content) {
@@ -542,5 +542,5 @@
                 }
             }
-            
+
             if (is_array($this->_data) && !empty($this->_data)) {
                 $xml_file_contents = $this->xml_serializer->serialize($this->_data);
@@ -549,5 +549,5 @@
         }
     }
-    
+
     /*
     * Writes content to the specified file.
@@ -587,5 +587,5 @@
         if ($fp = fopen($filename, 'w')) {
             if (flock($fp, LOCK_EX)) {
-                fwrite($fp, $content, mb_strlen($content));
+                fwrite($fp, $content);
                 flock($fp, LOCK_UN);
             } else {
@@ -639,5 +639,5 @@
         return true;
     }
-    
+
     /*
     * Delete all versions older than versions_min_days if there are more than versions_min_qty or 100.
@@ -714,8 +714,8 @@
             return false;
         }
-        
+
         // The file to restore.
         $version_file = sprintf('%s__%s.xml', preg_replace('/\.xml$/', '', $this->_data_file), $version);
-        
+
         // Ensure specified version exists.
         if (!file_exists($version_file)) {
Index: branches/eli_branch/lib/Prefs.inc.php
===================================================================
--- branches/eli_branch/lib/Prefs.inc.php	(revision 451)
+++ branches/eli_branch/lib/Prefs.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -24,10 +24,10 @@
  * Prefs.inc.php
  *
- * Prefs provides an API for saving arbitrary values in a user's session. 
+ * Prefs provides an API for saving arbitrary values in a user's session.
  * Session prefs can be stored into a database with the optional save() and load() methods.
  *
  * @author  Quinn Comendant <quinn@strangecode.com>
  * @version 2.1
- * 
+ *
  * Example of use:
 ---------------------------------------------------------------------
@@ -59,14 +59,14 @@
     // Configuration parameters for this object.
     var $_params = array(
-        
+
         // Enable database storage. If this is false, all prefs will live only as long as the session.
         'persistent' => false,
-        
+
         // The current user_id for which to load/save persistent preferences.
         'user_id' => null,
-        
+
         // How long before we force a reload of the persistent prefs data? 3600 = once every hour.
         'load_timeout' => 3600,
-        
+
         // Name of database table to store persistent prefs.
         'db_table' => 'pref_tbl',
@@ -85,7 +85,7 @@
 
         $this->_ns = $namespace;
-        
+
         // Initialized the prefs array.
-        if (!isset($_SESSION['_prefs'][$this->_ns])) {
+        if (!isset($_SESSION['_prefs'][$this->_ns]['saved'])) {
             $this->clear();
         }
@@ -160,5 +160,5 @@
     {
 		$app =& App::getInstance();
-    
+
         if (isset($this->_params[$param])) {
             return $this->_params[$param];
@@ -170,9 +170,9 @@
 
     /**
-     * Sets the default values for preferences. If a preference is not explicitly 
+     * Sets the default values for preferences. If a preference is not explicitly
      * set, the value set here will be used. Can be called multiple times to merge additional
      * defaults together.
      *
-     * @param  array $defaults  Array of key-value pairs 
+     * @param  array $defaults  Array of key-value pairs
      */
     function setDefaults($defaults)
@@ -200,11 +200,13 @@
             return false;
         }
-        
-        // Set a persistent preference if...
+
+        // Set a saved preference if...
         // - there isn't a default.
-        // - the new value is different than the default
-        // - there is a previously existing persistent key.
-        if (!isset($_SESSION['_prefs'][$this->_ns]['defaults'][$key]) || $_SESSION['_prefs'][$this->_ns]['defaults'][$key] != $val || isset($_SESSION['_prefs'][$this->_ns]['persistent'][$key])) {
-            $_SESSION['_prefs'][$this->_ns]['persistent'][$key] = $val;            
+        // - or the new value is different than the default
+        // - or there is a previously existing saved key.
+        if (!isset($_SESSION['_prefs'][$this->_ns]['defaults'][$key])
+        || $_SESSION['_prefs'][$this->_ns]['defaults'][$key] != $val
+        || isset($_SESSION['_prefs'][$this->_ns]['saved'][$key])) {
+            $_SESSION['_prefs'][$this->_ns]['saved'][$key] = $val;
             $app->logMsg(sprintf('Setting preference %s => %s', $key, truncate(getDump($val, true), 128, 'end')), LOG_DEBUG, __FILE__, __LINE__);
         } else {
@@ -214,5 +216,5 @@
 
     /**
-     * Returns the value of the requested preference. Persistent values take precedence, but if none is set
+     * Returns the value of the requested preference. Saved values take precedence, but if none is set
      * a default value is returned, or if not that, null.
      *
@@ -224,7 +226,7 @@
     {
         $app =& App::getInstance();
-        if (isset($_SESSION['_prefs'][$this->_ns]['persistent']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['persistent'])) {
-            $app->logMsg(sprintf('Found %s in persistent', $key), LOG_DEBUG, __FILE__, __LINE__);
-            return $_SESSION['_prefs'][$this->_ns]['persistent'][$key];
+        if (isset($_SESSION['_prefs'][$this->_ns]['saved']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['saved'])) {
+            $app->logMsg(sprintf('Found %s in saved', $key), LOG_DEBUG, __FILE__, __LINE__);
+            return $_SESSION['_prefs'][$this->_ns]['saved'][$key];
         } else if (isset($_SESSION['_prefs'][$this->_ns]['defaults']) && array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['defaults'])) {
             $app->logMsg(sprintf('Found %s in defaults', $key), LOG_DEBUG, __FILE__, __LINE__);
@@ -244,9 +246,9 @@
     function exists($key)
     {
-        return array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['persistent']);
-    }
-
-    /**
-     * Clear a set preference value. This will also remove the value from the database. 
+        return array_key_exists($key, $_SESSION['_prefs'][$this->_ns]['saved']);
+    }
+
+    /**
+     * Clear a set preference value. This will also remove the value from the database.
      *
      * @param string $key       The name of the preference to delete.
@@ -254,9 +256,9 @@
     function delete($key)
     {
-        unset($_SESSION['_prefs'][$this->_ns]['persistent'][$key]);
-    }
-
-    /**
-     * Resets the $_SESSION cache. This should be executed with the same consideration 
+        unset($_SESSION['_prefs'][$this->_ns]['saved'][$key]);
+    }
+
+    /**
+     * Resets the $_SESSION cache. This should be executed with the same consideration
      * as $auth->clear(), such as when logging out.
      */
@@ -269,5 +271,5 @@
                 'load_datetime' => '1970-01-01',
                 'defaults' => array(),
-                'persistent' => array(),
+                'saved' => array(),
             );
             break;
@@ -277,10 +279,10 @@
             break;
 
-        case 'persistent' :
-            $_SESSION['_prefs'][$this->_ns]['persistent'] = array();
+        case 'saved' :
+            $_SESSION['_prefs'][$this->_ns]['saved'] = array();
             break;
         }
     }
-    
+
     /*
     * Retrieves all prefs from the database and stores them in the $_SESSION.
@@ -297,5 +299,5 @@
         $app =& App::getInstance();
 		$db =& DB::getInstance();
-		
+
 		// Skip this method if not using the db.
 		if (true !== $this->getParam('persistent')) {
@@ -315,8 +317,8 @@
             return false;
         }
-        
+
         // Clear existing cache.
-        $this->clear('persistent');
-        
+        $this->clear('saved');
+
         // Retrieve all prefs for this user and namespace.
 		$qid = $db->query("
@@ -328,20 +330,20 @@
 		");
 		while (list($key, $val) = mysql_fetch_row($qid)) {
-            $_SESSION['_prefs'][$this->_ns]['persistent'][$key] = unserialize($val);
+            $_SESSION['_prefs'][$this->_ns]['saved'][$key] = unserialize($val);
 		}
-		
+
 		$app->logMsg(sprintf('Loaded %s prefs from database.', mysql_num_rows($qid)), LOG_DEBUG, __FILE__, __LINE__);
-		
+
 		// Data loaded only once per session.
 		$_SESSION['_prefs'][$this->_ns]['loaded'] = true;
         $_SESSION['_prefs'][$this->_ns]['load_datetime'] = date('Y-m-d H:i:s');
-		
+
 		return true;
     }
-    
+
     /*
     * Returns true if the prefs had been loaded from the database into the $_SESSION recently.
     * This function is simply a check so the database isn't access every page load.
-    * 
+    *
     * @access   private
     * @return   bool    True if prefs are loaded.
@@ -354,5 +356,5 @@
         if (isset($_SESSION['_prefs'][$this->_ns]['load_datetime'])
         && strtotime($_SESSION['_prefs'][$this->_ns]['load_datetime']) > time() - $this->getParam('load_timeout')
-        && isset($_SESSION['_prefs'][$this->_ns]['loaded']) 
+        && isset($_SESSION['_prefs'][$this->_ns]['loaded'])
         && true === $_SESSION['_prefs'][$this->_ns]['loaded']) {
             return true;
@@ -361,5 +363,5 @@
         }
     }
-    
+
     /*
     * Saves all prefs stored in the $_SESSION into the database.
@@ -375,10 +377,10 @@
         $app =& App::getInstance();
 		$db =& DB::getInstance();
-		
+
 		// Skip this method if not using the db.
 		if (true !== $this->getParam('persistent')) {
 		    return true;
 		}
-        
+
         // User_id must not be empty.
         if ('' == $this->getParam('user_id')) {
@@ -389,5 +391,5 @@
         $this->initDB();
 
-        if (isset($_SESSION['_prefs'][$this->_ns]['persistent']) && is_array($_SESSION['_prefs'][$this->_ns]['persistent']) && !empty($_SESSION['_prefs'][$this->_ns]['persistent'])) {
+        if (isset($_SESSION['_prefs'][$this->_ns]['saved']) && is_array($_SESSION['_prefs'][$this->_ns]['saved']) && !empty($_SESSION['_prefs'][$this->_ns]['saved'])) {
             // Delete old prefs from database.
             $db->query("
@@ -396,12 +398,12 @@
     		    AND pref_namespace = '" . $db->escapeString($this->_ns) . "'
             ");
-            
+
             // Insert new prefs.
             $insert_values = array();
-            foreach ($_SESSION['_prefs'][$this->_ns]['persistent'] as $key => $val) {
-                $insert_values[] = sprintf("('%s', '%s', '%s', '%s')", 
-                    $db->escapeString($this->getParam('user_id')), 
-                    $db->escapeString($this->_ns), 
-                    $db->escapeString($key), 
+            foreach ($_SESSION['_prefs'][$this->_ns]['saved'] as $key => $val) {
+                $insert_values[] = sprintf("('%s', '%s', '%s', '%s')",
+                    $db->escapeString($this->getParam('user_id')),
+                    $db->escapeString($this->_ns),
+                    $db->escapeString($key),
                     $db->escapeString(serialize($val))
                 );
@@ -409,13 +411,13 @@
             // TODO: after MySQL 5.0.23 is released this query could benefit from INSERT DELAYED.
             $db->query("
-                INSERT INTO " . $db->escapeString($this->getParam('db_table')) . " 
+                INSERT INTO " . $db->escapeString($this->getParam('db_table')) . "
                 (user_id, pref_namespace, pref_key, pref_value)
                 VALUES " . join(', ', $insert_values) . "
             ");
-            
+
             $app->logMsg(sprintf('Saved %s prefs to database.', sizeof($insert_values)), LOG_DEBUG, __FILE__, __LINE__);
             return true;
         }
-        
+
         return false;
     }
Index: branches/eli_branch/lib/SortOrder.inc.php
===================================================================
--- branches/eli_branch/lib/SortOrder.inc.php	(revision 451)
+++ branches/eli_branch/lib/SortOrder.inc.php	(revision 467)
@@ -24,5 +24,5 @@
  * SortOrder.inc.php
  *
- * SortOrder can determing how to sort results of a database query for display
+ * SortOrder can determine how to sort results of a database query for display
  * on a listing. It can print column headers that will be links to
  * automatically change the sort and order.
@@ -139,10 +139,12 @@
      *                               for example, for an alphabetical sort)
      */
-    public function set($sort = null, $order = null)
+    public function set($sort=null, $order=null, $save_value=true)
     {
         // Set new sort value.
         if (isset($sort)) {
             $this->sort_by = $sort;
-            $this->prefs->set('sort_by', $this->sort_by);
+            if ($save_value) {
+                $this->prefs->set('sort_by', $this->sort_by);
+            }
         }
 
@@ -150,5 +152,7 @@
         if (isset($order)) {
             $this->order = $order;
-            $this->prefs->set('sort_order', $this->order);
+            if ($save_value) {
+                $this->prefs->set('sort_order', $this->order);
+            }
         }
     }
Index: branches/eli_branch/lib/Utilities.inc.php
===================================================================
--- branches/eli_branch/lib/Utilities.inc.php	(revision 451)
+++ branches/eli_branch/lib/Utilities.inc.php	(revision 467)
@@ -4,5 +4,5 @@
  * For details visit the project site: <http://trac.strangecode.com/codebase/>
  * Copyright 2001-2012 Strangecode, LLC
- * 
+ *
  * This file is part of The Strangecode Codebase.
  *
@@ -11,10 +11,10 @@
  * Free Software Foundation, either version 3 of the License, or (at your option)
  * any later version.
- * 
+ *
  * The Strangecode Codebase is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
- * 
+ *
  * You should have received a copy of the GNU General Public License along with
  * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
@@ -33,30 +33,56 @@
  * @param  bool  $var_dump Use var_dump instead of print_r.
  */
-function dump($var, $display=false, $var_dump=false)
-{
+function dump($var, $display=false, $var_dump=false, $file='', $line='')
+{
+    if (defined('_CLI')) {
+        echo "\n$file $line\n";
+    } else {
+        echo $display ? "\n<br /><strong>$file $line</strong>\n<br /><pre>\n" : "\n\n\n<!--\n$file $line\n";
+    }
+    if ($var_dump) {
+        var_dump($var);
+    } else {
+        print_r($var);
+    }
     if (defined('_CLI')) {
         echo "\n";
-    } else {        
-        echo $display ? "\n<br /><pre>\n" : "\n\n\n<!--\n";
-    }
-    if ($var_dump) {
-        var_dump($var);
-    } else {
-        print_r($var);
-    }
-    if (defined('_CLI')) {
-        echo "\n";
-    } else {        
+    } else {
         echo $display ?  "\n</pre><br />\n" : "\n-->\n\n\n";
     }
 }
 
-/**
- * Return dump as variable.
- *
- * @param  mixed $var           Variable to dump.
- * @param  bool  $serialize     Remove line-endings. Useful for logging variables.
- * @return string Dump of var.
- */
+/*
+* Log a PHP variable to javascript console. Relies on getDump(), below.
+*
+* @access   public
+* @param    mixed   $var      The variable to dump.
+* @param    string  $prefix   A short note to print before the output to make identifying output easier.
+* @param    string  $file     The value of __FILE__.
+* @param    string  $line     The value of __LINE__.
+* @return   null
+* @author   Quinn Comendant <quinn@strangecode.com>
+*/
+function jsDump($var, $prefix='jsDump', $file='-', $line='-')
+{
+    if (!empty($var)) {
+        ?>
+        <script type="text/javascript" charset="utf-8">
+        /* <![CDATA[ */
+        window.console && console.log('<?php printf('%s: %s (on line %s of %s)', $prefix, str_replace("'", "\\'", getDump($var, true)), $line, $file); ?>');
+        /* ]]> */
+        </script>
+        <?php
+    }
+}
+
+/*
+* Return a string version of any variable, optionally serialized on one line.
+*
+* @access   public
+* @param    mixed   $var        The variable to dump.
+* @param    bool    $serialize  If true, remove line-endings. Useful for logging variables.
+* @return   string              The dumped variable.
+* @author   Quinn Comendant <quinn@strangecode.com>
+*/
 function getDump($var, $serialize=false)
 {
@@ -65,5 +91,5 @@
     $d = ob_get_contents();
     ob_end_clean();
-    return $serialize ? preg_replace('/\s+/m', '', $d) : $d;
+    return $serialize ? preg_replace('/\s+/m', ' ', $d) : $d;
 }
 
@@ -180,8 +206,8 @@
 {
     $words = preg_split('/[^\w]/', $search, -1, PREG_SPLIT_NO_EMPTY);
-    
+
     $search = array();
     $replace = array();
-    
+
     foreach ($words as $w) {
         if ('' != trim($w)) {
@@ -266,5 +292,11 @@
 
 /**
- * Turns "a really long string" into "a rea...string"
+ * Truncates "a really long string" into a string of specified length
+ * at the beginning: "âŠlong string"
+ * at the middle: "a reaâŠstring"
+ * or at the end: "a reallyâŠ".
+ *
+ * The regular expressions below first match and replace the string to the specified length and position,
+ * and secondly they remove any whitespace from around the delimiter (to avoid "this âŠ " from happening).
  *
  * @access  public
@@ -272,26 +304,26 @@
  * @param   int     $len    Maximum string length.
  * @param   string  $where  Where to cut the string. One of: 'start', 'middle', or 'end'.
- * @return  string          Truncated output string
+ * @return  string          Truncated output string.
  * @author  Quinn Comendant <quinn@strangecode.com>
  * @since   29 Mar 2006 13:48:49
  */
-function truncate($str, $len, $where='end', $delim='âŠ')
-{
-    if ($len <= 3 || mb_strlen($str) <= 3) {
-        return '';
-    }
-    $part1 = floor(($len - 3) / 2);
-    $part2 = ceil(($len - 3) / 2);
+function truncate($str, $len=50, $where='end', $delim='âŠ')
+{
+    $dlen = mb_strlen($delim);
+    if ($len <= $dlen || mb_strlen($str) <= $dlen) {
+        return substr($str, 0, $len);
+    }
+    $part1 = floor(($len - $dlen) / 2);
+    $part2 = ceil(($len - $dlen) / 2);
     switch ($where) {
     case 'start' :
-        return preg_replace(array(sprintf('/^.{4,}(.{%s})$/sU', $part1 + $part2), '/\s*\.{3,}\s*/sU'), array($delim . '$1', $delim), $str);
-        break;
+        return preg_replace(array(sprintf('/^.{%s,}(.{%s})$/sU', $dlen + 1, $part1 + $part2), sprintf('/\s*%s{%s,}\s*/sU', preg_quote($delim), $dlen)), array($delim . '$1', $delim), $str);
+
+    case 'middle' :
+        return preg_replace(array(sprintf('/^(.{%s}).{%s,}(.{%s})$/sU', $part1, $dlen + 1, $part2), sprintf('/\s*%s{%s,}\s*/sU', preg_quote($delim), $dlen)), array('$1' . $delim . '$2', $delim), $str);
+
+    case 'end' :
     default :
-    case 'middle' :
-        return preg_replace(array(sprintf('/^(.{%s}).{4,}(.{%s})$/sU', $part1, $part2), '/\s*\.{3,}\s*/sU'), array('$1' . $delim . '$2', $delim), $str);
-        break;    
-    case 'end' :
-        return preg_replace(array(sprintf('/^(.{%s}).{4,}$/sU', $part1 + $part2), '/\s*\.{3,}\s*/sU'), array('$1' . $delim, $delim), $str);
-        break;
+        return preg_replace(array(sprintf('/^(.{%s}).{%s,}$/sU', $part1 + $part2, $dlen + 1), sprintf('/\s*%s{%s,}\s*/sU', preg_quote($delim), $dlen)), array('$1' . $delim, $delim), $str);
     }
 }
@@ -307,5 +339,5 @@
 * @since    06 Dec 2008 17:04:01
 */
-if (!function_exists('mb_ucfirst')) {    
+if (!function_exists('mb_ucfirst')) {
     function mb_ucfirst($string)
     {
@@ -326,5 +358,5 @@
 * @since    20 Jan 2013 12:33:26
 */
-if (!function_exists('mb_strtr')) {    
+if (!function_exists('mb_strtr')) {
     function mb_strtr($string, $from, $to)
     {
@@ -367,5 +399,5 @@
 /*
 * Returns a human readable amount of time for the given amount of seconds.
-* 
+*
 * 45 seconds
 * 12 minutes
@@ -374,5 +406,5 @@
 * 1 week
 * 4 months
-* 
+*
 * Months are calculated using the real number of days in a year: 365.2422 / 12.
 *
@@ -400,5 +432,5 @@
         'century' => array(3155692608, _("century"), _("centuries")),
     );
-    
+
     // Max unit to calculate.
     $max_unit = isset($units[$max_unit]) ? $max_unit : 'year';
@@ -416,5 +448,5 @@
     }
     $final_time = sprintf($format, $final_time);
-    return sprintf('%s %s', $final_time, (1 == $final_time ? $units[$final_unit][1] : $units[$final_unit][2]));    
+    return sprintf('%s %s', $final_time, (1 == $final_time ? $units[$final_unit][1] : $units[$final_unit][2]));
 }
 
@@ -430,5 +462,5 @@
 {
     $app =& App::getInstance();
-    
+
     foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) {
         $fullpath = $path . DIRECTORY_SEPARATOR . $file;
@@ -680,5 +712,5 @@
  * escaped.  This is useful for putting values coming in from posted
  * checkboxes into a SET column of a database.
- * 
+ *
  *
  * @param  array $in      Array to convert.
@@ -688,5 +720,5 @@
 {
 	$db =& DB::getInstance();
-	
+
     if (is_array($in) && !empty($in)) {
         return join($separator, array_map(array($db, 'escapeString'), $in));
@@ -839,5 +871,5 @@
 {
     $app =& App::getInstance();
-    
+
     if ('' == trim($val)) {
         $app->logMsg(sprintf('Cannot add signature to an empty string.', null), LOG_INFO, __FILE__, __LINE__);
@@ -848,5 +880,5 @@
         $salt = $app->getParam('signing_key');
     }
-    
+
     // TODO: consider using more bits-per-character, such as done with:
     // http://www.php.net/manual/en/function.sha1.php#86239
@@ -916,5 +948,5 @@
 {
 	$app =& App::getInstance();
-	
+
 	$add_members = '/usr/lib/mailman/bin/add_members';
     /// FIXME: checking of executable is disabled.
@@ -948,5 +980,5 @@
 {
 	$app =& App::getInstance();
-	
+
     $remove_members = '/usr/lib/mailman/bin/remove_members';
     /// FIXME: checking of executable is disabled.
Index: branches/eli_branch/lib/Validator.inc.php
===================================================================
--- branches/eli_branch/lib/Validator.inc.php	(revision 451)
+++ branches/eli_branch/lib/Validator.inc.php	(revision 467)
@@ -218,4 +218,5 @@
     /**
      * Verifies that date can be processed by the strtotime function.
+     * Empty strings are considered valid. Other values are tested on their return value from strtotime(). Null values will fail.
      *
      * @param  string  $val The input data to validate.
@@ -226,5 +227,5 @@
 		$app =& App::getInstance();
 
-		if ('' == trim($val)) {
+		if (is_string($val) && '' === trim($val)) {
 		    // Don't be too bothered about empty strings.
 		    return true;
@@ -232,6 +233,5 @@
 
         $timestamp = strtotime($val);
-        // Return values change between php4 and php5.
-        if ('' != trim($val) && ($timestamp === -1 || $timestamp === false)) {
+        if (!$timestamp || $timestamp < 1) {
             return false;
         } else {
@@ -239,5 +239,4 @@
         }
     }
-
 
     /**
