diff --git a/WHATSNEW.md b/WHATSNEW.md
index 63abe0a617c3c5c558eda6c26dbc78c2d3dfebde..8cac25f814492d4a1790a948bbf959165d536223 100644
--- a/WHATSNEW.md
+++ b/WHATSNEW.md
@@ -1,3 +1,8 @@
+New stuff in 1.7-rc2
+====================
+  * Bug fixes from rc1
+  * Nested help topics support
+
 New stuff in 1.7-rc1
 ====================
   * Upgrade support for osTicket 1.6-rc1 and later
diff --git a/include/PasswordHash.php b/include/PasswordHash.php
index a30f41137c1334522168deb428869d60c7ead7b2..b5b8efcadbb70123ddedc61ae673c15342f94955 100644
--- a/include/PasswordHash.php
+++ b/include/PasswordHash.php
@@ -48,7 +48,7 @@ class PasswordHash {
 	function get_random_bytes($count)
 	{
 		$output = '';
-		if (is_readable('/dev/urandom') &&
+		if (@is_readable('/dev/urandom') &&
 		    ($fh = @fopen('/dev/urandom', 'rb'))) {
 			$output = fread($fh, $count);
 			fclose($fh);
diff --git a/include/ajax.content.php b/include/ajax.content.php
index e77f45d23014d2176b24500d31e26c1ab263133f..e97e96a5c3d1d894f5d7cacfad702c97ced25cf6 100644
--- a/include/ajax.content.php
+++ b/include/ajax.content.php
@@ -36,46 +36,48 @@ class ContentAjaxAPI extends AjaxController {
 
     function ticket_variables() {
 
-        $content='<div style="width:600px;">
-                    <h2>Ticket Variables</h2>
-                    Please note that non-base variables depends on the context of use.
-                    <br>
-                    <table width="100%" border="0" cellspacing=1 cellpadding=2>
-                        <tr><td width="50%" valign="top"><b>Base Variables</b></td><td><b>Other Variables</b></td></tr>
-                        <tr>
-                            <td width="50%" valign="top">
-                                <table width="100%" border="0" cellspacing=1 cellpadding=1>
-                                    <tr><td width="100">%id</td><td>Ticket ID (internal ID)</td></tr>
-                                    <tr><td>%ticket</td><td>Ticket number (external ID)</td></tr>
-                                    <tr><td>%email</td><td>Email address</td></tr>
-                                    <tr><td>%name</td><td>Full name</td></tr>
-                                    <tr><td>%subject</td><td>Subject</td></tr>
-                                    <tr><td>%topic</td><td>Help topic (web only)</td></tr>
-                                    <tr><td>%phone</td><td>Phone number | ext</td></tr>
-                                    <tr><td>%status</td><td>Status</td></tr>
-                                    <tr><td>%priority</td><td>Priority</td></tr>
-                                    <tr><td>%dept</td><td>Department</td></tr>
-                                    <tr><td>%assigned</td><td>Assigned staff or team (if any)</td></tr>
-                                    <tr><td>%createdate</td><td>Date created</td></tr>
-                                    <tr><td>%duedate</td><td>Due date</td></tr>
-                                    <tr><td>%closedate</td><td>Date closed</td></tr>
-                                </table>
-                            </td>
-                            <td valign="top">
-                                <table width="100%" border="0" cellspacing=1 cellpadding=1>
-                                    <tr><td width="100">%message</td><td>Message (incoming)</td></tr>
-                                    <tr><td>%response</td><td>Response (outgoing)</td></tr>
-                                    <tr><td>%note</td><td>Internal/transfer note</td></tr>
-                                    <tr><td>%staff</td><td>Staff\'s name (alert/notices)</td></tr>
-                                    <tr><td>%assignee</td><td>Assigned staff</td></tr>
-                                    <tr><td>%assigner</td><td>Staff assigning the ticket</td></tr>
-                                    <tr><td>%url</td><td>osTicket\'s base url (FQDN)</td></tr>
-
-                                </table>
-                            </td>
-                        </tr>
+        $content='
+<div style="width:600px;">
+    <h2>Ticket Variables</h2>
+    Please note that non-base variables depends on the context of use.
+    <br/>
+    <table width="100%" border="0" cellspacing=1 cellpadding=2>
+        <tr><td width="50%" valign="top"><b>Base Variables</b></td><td><b>Other Variables</b></td></tr>
+        <tr>
+            <td width="50%" valign="top">
+                <table width="100%" border="0" cellspacing=1 cellpadding=1>
+                    <tr><td width="100">%id</td><td>Ticket ID (internal ID)</td></tr>
+                    <tr><td>%ticket</td><td>Ticket number (external ID)</td></tr>
+                    <tr><td>%email</td><td>Email address</td></tr>
+                    <tr><td>%name</td><td>Full name</td></tr>
+                    <tr><td>%subject</td><td>Subject</td></tr>
+                    <tr><td>%topic</td><td>Help topic (web only)</td></tr>
+                    <tr><td>%phone</td><td>Phone number | ext</td></tr>
+                    <tr><td>%status</td><td>Status</td></tr>
+                    <tr><td>%priority</td><td>Priority</td></tr>
+                    <tr><td>%dept</td><td>Department</td></tr>
+                    <tr><td>%assigned</td><td>Assigned staff or team (if any)</td></tr>
+                    <tr><td>%createdate</td><td>Date created</td></tr>
+                    <tr><td>%duedate</td><td>Due date</td></tr>
+                    <tr><td>%closedate</td><td>Date closed</td></tr>
+                </table>
+            </td>
+            <td valign="top">
+                <table width="100%" border="0" cellspacing=1 cellpadding=1>
+                    <tr><td width="100">%message</td><td>Message (incoming)</td></tr>
+                    <tr><td>%response</td><td>Response (outgoing)</td></tr>
+                    <tr><td>%note</td><td>Internal/transfer note</td></tr>
+                    <tr><td>%staff</td><td>Staff\'s name (alert/notices)</td></tr>
+                    <tr><td>%assignee</td><td>Assigned staff</td></tr>
+                    <tr><td>%assigner</td><td>Staff assigning the ticket</td></tr>
+                    <tr><td>%url</td><td>osTicket\'s base url (FQDN)</td></tr>
+                    <tr><td>%auth</td><td>Client authentication token</td></tr>
+                    <tr><td>%clientlink</td><td>Client auto-login link</td></tr>
                 </table>
-            </div>';
+            </td>
+        </tr>
+    </table>
+</div>';
 
         return $content;
     }
diff --git a/include/class.canned.php b/include/class.canned.php
index 399b490d3a9cf3c1832fc4892c66ccd4aed06f6f..52a487529c368bc158777359260d36b808dc1d90 100644
--- a/include/class.canned.php
+++ b/include/class.canned.php
@@ -270,14 +270,14 @@ class Canned {
             if(db_query($sql))
                 return true;
 
-            $errors['err']='Unable to update canned reply.';
+            $errors['err']='Unable to update canned response.';
 
         } else {
             $sql='INSERT INTO '.CANNED_TABLE.' SET '.$sql.',created=NOW()';
             if(db_query($sql) && ($id=db_insert_id()))
                 return $id;
 
-            $errors['err']='Unable to create the canned reply. Internal error';
+            $errors['err']='Unable to create the canned response. Internal error';
         }
 
         return false;
diff --git a/include/class.client.php b/include/class.client.php
index 8786c0e19cdb9719a86a556b3ce26795ac5ce62f..5c5f3035ee6b485d6862950b35924f00e0f90b97 100644
--- a/include/class.client.php
+++ b/include/class.client.php
@@ -133,5 +133,73 @@ class Client {
     function lookupByEmail($email) {
         return (($id=self::getLastTicketIdByEmail($email)))?self::lookup($id, $email):null;
     }
+
+    /* static */ function tryLogin($ticketID, $email, $auth=null) {
+        global $ost;
+        $cfg = $ost->getConfig();
+
+        # Only consider auth token for GET requests, and for GET requests,
+        # REQUIRE the auth token
+        $auto_login = $_SERVER['REQUEST_METHOD'] == 'GET';
+
+        //Check time for last max failed login attempt strike.
+        $loginmsg='Invalid login';
+        # XXX: SECURITY: Max attempts is enforced client-side via the PHP
+        #      session cookie.
+        if($_SESSION['_client']['laststrike']) {
+            if((time()-$_SESSION['_client']['laststrike'])<$cfg->getClientLoginTimeout()) {
+                $loginmsg='Excessive failed login attempts';
+                $errors['err']='You\'ve reached maximum failed login attempts allowed. Try again later or <a href="open.php">open a new ticket</a>';
+            }else{ //Timeout is over.
+                //Reset the counter for next round of attempts after the timeout.
+                $_SESSION['_client']['laststrike']=null;
+                $_SESSION['_client']['strikes']=0;
+            }
+        }
+        //See if we can fetch local ticket id associated with the ID given
+        if(!$errors && is_numeric($ticketID) && Validator::is_email($email) && ($ticket=Ticket::lookupByExtId($ticketID))) {
+            //At this point we know the ticket is valid.
+            //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? 
+            //Check the email given.
+            # Require auth token for automatic logins
+            if (!$auto_login || $auth === $ticket->getAuthToken()) {
+                if($ticket->getId() && strcasecmp($ticket->getEmail(),$email)==0){
+                    //valid match...create session goodies for the client.
+                    $user = new ClientSession($email,$ticket->getId());
+                    $_SESSION['_client']=array(); //clear.
+                    $_SESSION['_client']['userID']   =$ticket->getEmail(); //Email
+                    $_SESSION['_client']['key']      =$ticket->getExtId(); //Ticket ID --acts as password when used with email. See above.
+                    $_SESSION['_client']['token']    =$user->getSessionToken();
+                    $_SESSION['TZ_OFFSET']=$cfg->getTZoffset();
+                    $_SESSION['TZ_DST']=$cfg->observeDaylightSaving();
+                    //Log login info...
+                    $msg=sprintf("%s/%s logged in [%s]",$ticket->getEmail(),$ticket->getExtId(),$_SERVER['REMOTE_ADDR']);
+                    $ost->logDebug('User login', $msg);
+                    //Redirect tickets.php
+                    session_write_close();
+                    session_regenerate_id();
+                    @header("Location: tickets.php?id=".$ticket->getExtId());
+                    require_once('tickets.php'); //Just incase. of header already sent error.
+                    exit;
+                }
+            }
+        }
+        //If we get to this point we know the login failed.
+        $_SESSION['_client']['strikes']+=1;
+        if(!$errors && $_SESSION['_client']['strikes']>$cfg->getClientMaxLogins()) {
+            $loginmsg='Access Denied';
+            $errors['err']='Forgot your login info? Please <a href="open.php">open a new ticket</a>.';
+            $_SESSION['_client']['laststrike']=time();
+            $alert='Excessive login attempts by a client?'."\n".
+                    'Email: '.$_POST['lemail']."\n".'Ticket#: '.$_POST['lticket']."\n".
+                    'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n".
+                    'Attempts #'.$_SESSION['_client']['strikes'];
+            $ost->logError('Excessive login attempts (client)', $alert, ($cfg->alertONLoginError()));
+        }elseif($_SESSION['_client']['strikes']%2==0){ //Log every other failed login attempt as a warning.
+            $alert='Email: '.$_POST['lemail']."\n".'Ticket #: '.$_POST['lticket']."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
+                   "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_client']['strikes'];
+            $ost->logWarning('Failed login attempt (client)', $alert);
+        }
+    }
 }
 ?>
diff --git a/include/class.file.php b/include/class.file.php
index c27c9fdd07b5aa7477336c009af2fdb75605233c..e4012bb4b9f7665438cc28fbc3818162f48579a7 100644
--- a/include/class.file.php
+++ b/include/class.file.php
@@ -108,7 +108,7 @@ class AttachmentFile {
     function display() {
        
 
-        header('Content-type: '.$this->getType()?$this->getType():'application/octet-stream');
+        header('Content-Type: '.($this->getType()?$this->getType():'application/octet-stream'));
         header('Content-Length: '.$this->getSize());
         echo $this->getData();
         exit();
@@ -120,9 +120,7 @@ class AttachmentFile {
         header('Expires: 0');
         header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
         header('Cache-Control: public');
-        header('Content-Type: application/octet-stream');
-
-        //header('Content-Type: '.$this->getType()?$this->getType():'application/octet-stream');
+        header('Content-Type: '.($this->getType()?$this->getType():'application/octet-stream'));
     
         $filename=basename($this->getName());
         $user_agent = strtolower ($_SERVER['HTTP_USER_AGENT']);
diff --git a/include/class.filter.php b/include/class.filter.php
index bc9b0847132aff00f794dd74abf6b2ec71379e35..b6c81b42b60d0d4b8c67d3f7b33b1138695fa1e7 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -236,9 +236,9 @@ class Filter {
         );
         $match = false;
         # Respect configured filter email-id
-        if ($email['emailId'] && $this->getEmailId()
-                && $this->getEmailId() != $email['emailId'])
+        if ($this->getEmailId() && $this->getEmailId() != $email['emailId'])
             return false;
+
         foreach ($this->getRules() as $rule) {
             list($func, $pos, $neg) = $how[$rule['h']];
             # TODO: convert $what and $rule['v'] to mb_strtoupper and do
diff --git a/include/class.nav.php b/include/class.nav.php
index a5ce84cb07affcec52e9ecec88460b790ece4fb6..0d5fddcbf3a48772db052a71363bfe0fb3b64ad5 100644
--- a/include/class.nav.php
+++ b/include/class.nav.php
@@ -123,12 +123,12 @@ class StaffNav {
                     $subnav[]=array('desc'=>'My&nbsp;Profile','href'=>'profile.php','iconclass'=>'users');
                     break;
                 case 'kbase':
-                    $subnav[]=array('desc'=>'Knowledgebase','href'=>'kb.php', 'urls'=>array('faq.php'), 'iconclass'=>'kb');
+                    $subnav[]=array('desc'=>'FAQs','href'=>'kb.php', 'urls'=>array('faq.php'), 'iconclass'=>'kb');
                     if($staff) {
                         if($staff->canManageFAQ())
-                            $subnav[]=array('desc'=>'Categories','href'=>'categories.php','iconclass'=>'kb-categories');
+                            $subnav[]=array('desc'=>'Categories','href'=>'categories.php','iconclass'=>'faq-categories');
                         if($staff->canManageCannedResponses())
-                            $subnav[]=array('desc'=>'Canned&nbsp;Replies','href'=>'canned.php','iconclass'=>'canned');
+                            $subnav[]=array('desc'=>'Canned&nbsp;Responses','href'=>'canned.php','iconclass'=>'canned');
                     }
                    break;
             }
diff --git a/include/class.staff.php b/include/class.staff.php
index b607f6eac145aa7e7c13547218d936f7662ceb8a..83c9ce2e58da2905c4716a28ff159dfb870074b1 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -82,20 +82,28 @@ class Staff {
     }
 
     /*compares user password*/
-    function check_passwd($password) {
+    function check_passwd($password, $autoupdate=true) {
 
         /*bcrypt based password match*/
         if(Passwd::cmp($password, $this->getPasswd()))
             return true;
 
-        /*Fall back to MD5 && force a password reset if it matches*/
-        if(strlen($this->getPasswd()) && !strcmp($this->getPasswd(), MD5($password))) {
+        //Fall back to MD5
+        if(!$password || strcmp($this->getPasswd(), MD5($password)))
+            return false;
+
+        //Password is a MD5 hash: rehash it (if enabled) otherwise force passwd change.
+        $sql='UPDATE '.STAFF_TABLE.' SET passwd='.db_input(Passwd::hash($password))
+            .' WHERE staff_id='.db_input($this->getId());
+
+        if(!$autoupdate || !db_query($sql))
             $this->forcePasswdRest();
 
-            return true;
-        }
+        return true;
+    }
 
-        return false;
+    function cmp_passwd($password) {
+        return $this->check_passwd($password, false);
     }
 
     function forcePasswdRest() {
@@ -406,8 +414,10 @@ class Staff {
             
             if(!$vars['cpasswd'])
                 $errors['cpasswd']='Current password required';
-            elseif(!$this->check_passwd($vars['cpasswd']))
+            elseif(!$this->cmp_passwd($vars['cpasswd']))
                 $errors['cpasswd']='Invalid current password!';
+            elseif(!strcasecmp($vars['passwd1'], $vars['cpasswd']))
+                $errors['passwd1']='New password MUST be different from the current password!';
         }
 
         if(!$vars['timezone_id'])
diff --git a/include/class.ticket.php b/include/class.ticket.php
index da45d51935322d606f6e6b60b102c6c63ea363b8..8b9581d532a1e94c8076d3eca0b82bcfe88d7d0e 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -74,7 +74,7 @@ class Ticket{
 
         //TODO: delete helptopic field in ticket table.
        
-        $sql='SELECT  ticket.*, topic.topic as helptopic, lock_id, dept_name, priority_desc '
+        $sql='SELECT  ticket.*, lock_id, dept_name, priority_desc '
             .' ,count(attach.attach_id) as attachments '
             .' ,count(DISTINCT message.id) as messages '
             .' ,count(DISTINCT response.id) as responses '
@@ -83,8 +83,6 @@ class Ticket{
             .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) '
             .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON ('
                 .'ticket.priority_id=pri.priority_id) '
-            .' LEFT JOIN '.TOPIC_TABLE.' topic ON ('
-                .'ticket.topic_id=topic.topic_id) '
             .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON ('
                 .'ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) '
             .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON ('
@@ -128,7 +126,6 @@ class Ticket{
         $this->dept_name = $this->ht['dept_name'];
         $this->sla_id = $this->ht['sla_id'];
         $this->topic_id = $this->ht['topic_id'];
-        $this->helptopic = $this->ht['helptopic'];
         $this->subject = $this->ht['subject'];
         $this->overdue = $this->ht['isoverdue'];
         
@@ -213,6 +210,11 @@ class Ticket{
         return $this->email;
     }
 
+    function getAuthToken() {
+        # XXX: Support variable email address (for CCs)
+        return md5($this->getId() . $this->getEmail() . SECRET_SALT);
+    }
+
     function getName(){
         return $this->fullname;
     }
@@ -227,7 +229,7 @@ class Ticket{
         if(!$this->helpTopic && ($topic=$this->getTopic()))
             $this->helpTopic = $topic->getName();
             
-        return $this->helptopic;
+        return $this->helpTopic;
     }
    
     function getCreateDate(){
@@ -417,14 +419,14 @@ class Ticket{
         return $assignees;
     }
 
-    function getTopicId(){
+    function getTopicId() {
         return $this->topic_id;
     }
 
     function getTopic() { 
 
         if(!$this->topic && $this->getTopicId())
-            $this->topic = Topic::lookup($this->getTopicId);
+            $this->topic = Topic::lookup($this->getTopicId());
 
         return $this->topic;
     }
@@ -976,7 +978,6 @@ class Ticket{
                 $email->send($this->getEmail(),$subj,$body);
             }
         }
-
     }
 
     function onAssign($note, $alert=true) {
@@ -1105,7 +1106,8 @@ class Ticket{
 
 
         $search = array('/%id/','/%ticket/','/%email/','/%name/','/%subject/','/%topic/','/%phone/','/%status/','/%priority/',
-                        '/%dept/','/%assigned_staff/','/%createdate/','/%duedate/','/%closedate/','/%url/');
+                        '/%dept/','/%assigned_staff/','/%createdate/','/%duedate/','/%closedate/','/%url/',
+                        '/%auth/', '/%clientlink/');
         $replace = array($this->getId(),
                          $this->getExtId(),
                          $this->getEmail(),
@@ -1120,13 +1122,15 @@ class Ticket{
                          Format::db_daydatetime($this->getCreateDate()),
                          Format::db_daydatetime($this->getDueDate()),
                          Format::db_daydatetime($this->getCloseDate()),
-                         $cfg->getBaseUrl());
-        return preg_replace($search,$replace,$text);
+                         $cfg->getBaseUrl(),
+                         $this->getAuthToken(),
+                         '%url/view.php?t=%ticket&e=%email&a=%auth');
+        while ($text != ($T = preg_replace($search,$replace,$text))) {
+            $text = $T;
+        }
+        return $text;
     }
 
-
-
-
     function markUnAnswered() {
         return (!$this->isAnswered() || $this->setAnsweredState(0));
     }
@@ -1138,7 +1142,6 @@ class Ticket{
     function markOverdue($whine=true) {
         
         global $cfg;
-
         
         if($this->isOverdue())
             return true;
@@ -1297,14 +1300,11 @@ class Ticket{
        
         if(!$this->getId()) return 0;
 
-
-            
         //Strip quoted reply...on emailed replies
         if(!strcasecmp($source, 'Email') 
                 && $cfg->stripQuotedReply() 
-                && ($tag=$cfg->getReplySeparator()) && strpos($msg, $tag))
-            list($msg)=split($tag, $msg);
-
+                && ($tag=$cfg->getReplySeparator()) && strpos($message, $tag))
+            list($message)=split($tag, $message);
 
         # XXX: Refuse auto-response messages? (via email) XXX: No - but kill our auto-responder.
 
diff --git a/include/class.topic.php b/include/class.topic.php
index 40ab8096bc1831b821ea37754b18e3d1a1a22e3e..c8e6a9e72b9a8d26da82e97f48cfc9f25e97d51c 100644
--- a/include/class.topic.php
+++ b/include/class.topic.php
@@ -16,11 +16,11 @@
 
 class Topic {
     var $id;
-    var $topic;
  
     var $ht;
+    var $parent;
     
-    function Topic($id){
+    function Topic($id) {
         $this->id=0;
         $this->load($id);
     }
@@ -30,12 +30,16 @@ class Topic {
         if(!$id && !($id=$this->getId()))
             return false;
 
-        $sql='SELECT * FROM '.TOPIC_TABLE
-            .' WHERE topic_id='.db_input($id);
+        $sql='SELECT ht.* '
+            .', IF(ht.topic_pid IS NULL, ht.topic, CONCAT_WS(" / ", ht2.topic, ht.topic)) as name '
+            .' FROM '.TOPIC_TABLE.' ht '
+            .' LEFT JOIN '.TOPIC_TABLE.' ht2 ON(ht2.topic_id=ht.topic_pid) '
+            .' WHERE ht.topic_id='.db_input($id);
+
         if(!($res=db_query($sql)) || !db_num_rows($res))
             return false;
 
-        $this->ht=db_fetch_array($res);
+        $this->ht = db_fetch_array($res);
         $this->id=$this->ht['topic_id'];
     
         return true;
@@ -45,31 +49,42 @@ class Topic {
         return $this->load();
     }
     
-    function getId(){
+    function getId() {
         return $this->id;
     }
-    
-    function getName(){
-        return $this->ht['topic'];
+
+    function getPid() {
+        return $this->ht['topic_pid'];
+    }
+
+    function getParent() {
+        if(!$this->parent && $this->getPid())
+            $this->parent = self::lookup($this->getPid());
+
+        return $this->parent;
+    }
+
+    function getName() {
+        return $this->ht['name'];
     }
     
-    function getDeptId(){
+    function getDeptId() {
         return $this->ht['dept_id'];
     }
 
-    function getSLAId(){
+    function getSLAId() {
         return $this->ht['sla_id'];
     }
 
-    function getPriorityId(){
+    function getPriorityId() {
         return $this->ht['priority_id'];
     }
 
-    function getStaffId(){
+    function getStaffId() {
         return $this->ht['staff_id'];
     }
 
-    function getTeamId(){
+    function getTeamId() {
         return $this->ht['team_id'];
     }
     
@@ -81,11 +96,11 @@ class Topic {
          return ($this->ht['isactive']);
     }
 
-    function isActive(){
+    function isActive() {
         return $this->isEnabled();
     }
 
-    function isPublic(){
+    function isPublic() {
         return ($this->ht['ispublic']);
     }
 
@@ -97,18 +112,20 @@ class Topic {
         return $this->getHashtable();
     }
 
-    function update($vars,&$errors) {
+    function update($vars, &$errors) {
 
-        if($this->save($this->getId(),$vars,$errors)){
-            $this->reload();
-            return true;
-        }
-        return false;
+        if(!$this->save($this->getId(), $vars, $errors))
+            return false;
+
+        $this->reload();
+        return true;
     }
 
-    function delete(){
+    function delete() {
+
         $sql='DELETE FROM '.TOPIC_TABLE.' WHERE topic_id='.db_input($this->getId()).' LIMIT 1';
-        if(db_query($sql) && ($num=db_affected_rows())){
+        if(db_query($sql) && ($num=db_affected_rows())) {
+            db_query('UPDATE '.TOPIC_TABLE.' SET topic_pid=0 WHERE topic_pid='.db_input($this->getId()));
             db_query('UPDATE '.TICKET_TABLE.' SET topic_id=0 WHERE topic_id='.db_input($this->getId()));
             db_query('DELETE FROM '.FAQ_TOPIC_TABLE.' WHERE topic_id='.db_input($this->getId()));
         }
@@ -117,19 +134,24 @@ class Topic {
     }
     /*** Static functions ***/
     function create($vars,&$errors) { 
-        return self::save(0,$vars,$errors);
+        return self::save(0, $vars, $errors);
     }
 
     function getHelpTopics($publicOnly=false) {
 
         $topics=array();
-        $sql='SELECT topic_id, topic FROM '.TOPIC_TABLE
-            .' WHERE isactive=1';
+        $sql='SELECT ht.topic_id'
+            .', IF(ht2.topic_pid IS NULL, ht.topic, CONCAT_WS(" / ", ht2.topic, ht.topic)) as name '
+            .' FROM '.TOPIC_TABLE. ' ht '
+            .' LEFT JOIN '.TOPIC_TABLE.' ht2 ON(ht2.topic_id=ht.topic_pid) '
+            .' WHERE ht.isactive=1';
+
         if($publicOnly)
-            $sql.=' AND ispublic=1';
-        $sql.=' ORDER BY topic';
+            $sql.=' AND ht.ispublic=1';
+
+        $sql.=' ORDER BY name';
         if(($res=db_query($sql)) && db_num_rows($res))
-            while(list($id,$name)=db_fetch_row($res))
+            while(list($id, $name)=db_fetch_row($res))
                 $topics[$id]=$name;
 
         return $topics;
@@ -139,8 +161,7 @@ class Topic {
         return self::getHelpTopics(true);
     }
 
-
-    function getIdByName($topic){
+    function getIdByName($topic) {
         $sql='SELECT topic_id FROM '.TOPIC_TABLE.' WHERE topic='.db_input($topic);
         if(($res=db_query($sql)) && db_num_rows($res))
             list($id)=db_fetch_row($res);
@@ -148,11 +169,11 @@ class Topic {
         return $id;
     }
 
-    function lookup($id){
+    function lookup($id) {
         return ($id && is_numeric($id) && ($t= new Topic($id)) && $t->getId()==$id)?$t:null;
     }
 
-    function save($id,$vars,&$errors) {
+    function save($id, $vars, &$errors) {
 
         $vars['topic']=Format::striptags(trim($vars['topic']));
 
@@ -174,22 +195,24 @@ class Topic {
         
         if($errors) return false;
 
-        $sql=' updated=NOW(),topic='.db_input($vars['topic']).
-             ',dept_id='.db_input($vars['dept_id']).
-             ',priority_id='.db_input($vars['priority_id']).
-             ',sla_id='.db_input($vars['sla_id']).
-             ',isactive='.db_input($vars['isactive']).
-             ',ispublic='.db_input($vars['ispublic']).
-             ',noautoresp='.db_input(isset($vars['noautoresp'])?1:0).
-             ',notes='.db_input($vars['notes']);
+        $sql=' updated=NOW() '
+            .',topic='.db_input($vars['topic'])
+            .',topic_pid='.db_input($vars['pid'])
+            .',dept_id='.db_input($vars['dept_id'])
+            .',priority_id='.db_input($vars['priority_id'])
+            .',sla_id='.db_input($vars['sla_id'])
+            .',isactive='.db_input($vars['isactive'])
+            .',ispublic='.db_input($vars['ispublic'])
+            .',noautoresp='.db_input(isset($vars['noautoresp'])?1:0)
+            .',notes='.db_input($vars['notes']);
 
         //Auto assign ID is overloaded...
         if($vars['assign'] && $vars['assign'][0]=='s')
-             $sql.=',team_id=0,staff_id='.db_input(preg_replace("/[^0-9]/", "",$vars['assign']));
+             $sql.=',team_id=0, staff_id='.db_input(preg_replace("/[^0-9]/", "", $vars['assign']));
         elseif($vars['assign'] && $vars['assign'][0]=='t')
-            $sql.=',staff_id=0,team_id='.db_input(preg_replace("/[^0-9]/", "",$vars['assign']));
+            $sql.=',staff_id=0, team_id='.db_input(preg_replace("/[^0-9]/", "", $vars['assign']));
         else
-            $sql.=',staff_id=0,team_id=0 '; //no auto-assignment!
+            $sql.=',staff_id=0, team_id=0 '; //no auto-assignment!
             
         if($id) {
             $sql='UPDATE '.TOPIC_TABLE.' SET '.$sql.' WHERE topic_id='.db_input($id);
@@ -197,7 +220,7 @@ class Topic {
                 return true;
 
             $errors['err']='Unable to update topic. Internal error occurred';
-        }else{
+        } else {
             $sql='INSERT INTO '.TOPIC_TABLE.' SET '.$sql.',created=NOW()';
             if(db_query($sql) && ($id=db_insert_id()))
                 return $id;
diff --git a/include/client/faq.inc.php b/include/client/faq.inc.php
index 65f770e9673083d2474d2a9eb260771492541d41..d0be23c9fd41b1e9d9572bdcdd854623e5e51a0c 100644
--- a/include/client/faq.inc.php
+++ b/include/client/faq.inc.php
@@ -7,7 +7,7 @@ $category=$faq->getCategory();
 <h1>Frequently Asked Questions</h1>
 <div id="breadcrumbs">
     <a href="index.php">All Categories</a>
-    &raquo; <a href="faq.php?cid=<? echo $category->getId(); ?>"><? echo $category->getName(); ?></a>
+    &raquo; <a href="faq.php?cid=<?php echo $category->getId(); ?>"><?php echo $category->getName(); ?></a>
 </div>
 <div style="width:700;padding-top:2px; float:left;">
 <strong style="font-size:16px;"><?php echo $faq->getQuestion() ?></strong>
@@ -21,8 +21,8 @@ $category=$faq->getCategory();
 <?php
 if($faq->getNumAttachments()) { ?>
  <div><span class="faded"><b>Attachments:</b></span>  <?php echo $faq->getAttachmentsLinks(); ?></div>
-<?
-}?>
+<?php
+} ?>
 
 <div class="article-meta"><span class="faded"><b>Help Topics:</b></span>
     <?php echo ($topics=$faq->getHelpTopics())?implode(', ',$topics):' '; ?>
diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php
index 7719ec74a7ef2a58babcae7112a0d2cb05caa92e..1ee781a908a4ba275ca734f1d62be5d684198b9a 100644
--- a/include/client/tickets.inc.php
+++ b/include/client/tickets.inc.php
@@ -147,12 +147,12 @@ $negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting
                 <a class="Icon <?php echo strtolower($row['source']); ?>Ticket" title="<?php echo $row['email']; ?>" 
                     href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $ticketID; ?></a>
                 </td>
-                <td>&nbsp;<?=Format::db_date($row['created'])?></td>
-                <td>&nbsp;<?=ucfirst($row['status'])?></td>
+                <td>&nbsp;<?php echo Format::db_date($row['created']); ?></td>
+                <td>&nbsp;<?php echo ucfirst($row['status']); ?></td>
                 <td>
                     <a href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $subject; ?></a>
                 </td>
-                <td>&nbsp;<?=Format::truncate($dept,30)?></td>
+                <td>&nbsp;<?php echo Format::truncate($dept,30); ?></td>
                 <td><?php echo $phone; ?></td>
             </tr>
         <?php
diff --git a/include/pear/Auth/SASL/DigestMD5.php b/include/pear/Auth/SASL/DigestMD5.php
index 4534e500bb35712acc25b87f4272f6ba39132e42..e97e15daba0c01f2cc361ecffec3cd177fdb7ee0 100644
--- a/include/pear/Auth/SASL/DigestMD5.php
+++ b/include/pear/Auth/SASL/DigestMD5.php
@@ -178,10 +178,10 @@ class Auth_SASL_DigestMD5 extends Auth_SASL_Common
     */
     function _getCnonce()
     {
-        if (file_exists('/dev/urandom') && $fd = @fopen('/dev/urandom', 'r')) {
+        if (@file_exists('/dev/urandom') && $fd = @fopen('/dev/urandom', 'r')) {
             return base64_encode(fread($fd, 32));
 
-        } elseif (file_exists('/dev/random') && $fd = @fopen('/dev/random', 'r')) {
+        } elseif (@file_exists('/dev/random') && $fd = @fopen('/dev/random', 'r')) {
             return base64_encode(fread($fd, 32));
 
         } else {
diff --git a/include/staff/cannedreply.inc.php b/include/staff/cannedresponse.inc.php
similarity index 92%
rename from include/staff/cannedreply.inc.php
rename to include/staff/cannedresponse.inc.php
index f18b114a2225fde48d9bddbc73ff3ec93e5a3fd4..cc495d534c919e4954e35a4e3db325746f7d2b4e 100644
--- a/include/staff/cannedreply.inc.php
+++ b/include/staff/cannedresponse.inc.php
@@ -3,16 +3,16 @@ if(!defined('OSTSCPINC') || !$thisstaff) die('Access Denied');
 $info=array();
 $qstr='';
 if($canned && $_REQUEST['a']!='add'){
-    $title='Update Canned Reply';
+    $title='Update Canned Response';
     $action='update';
     $submit_text='Save Changes';
     $info=$canned->getInfo();
     $info['id']=$canned->getId();
     $qstr.='&id='.$canned->getId();
 }else {
-    $title='Add New Canned Reply';
+    $title='Add New Canned Response';
     $action='create';
-    $submit_text='Add Reply';
+    $submit_text='Add Response';
     $info['isenabled']=isset($info['isenabled'])?$info['isenabled']:1;
     $qstr.='&a='.$_REQUEST['a'];
 }
@@ -24,13 +24,13 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
- <h2>Canned Reply</h2>
+ <h2>Canned Response</h2>
  <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
         <tr>
             <th colspan="2">
                 <h4><?php echo $title; ?></h4>
-                <em>Canned reply settings</em>
+                <em>Canned response settings</em>
             </th>
         </tr>
     </thead>
@@ -63,7 +63,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
         <tr>
             <th colspan="2">
-                <em><strong>Canned Reply</strong>: Make the title short and clear.&nbsp;</em>
+                <em><strong>Canned Response</strong>: Make the title short and clear.&nbsp;</em>
             </th>
         </tr>
         <tr>
@@ -92,13 +92,14 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <div>
                     <input type="file" name="attachments[]" value=""/>
                 </div>
-                <?}?>
+                <?php 
+                }?>
                 <div class="faded">You can upload up to 10 attachments per canned response.</div>
             </td>
         </tr>
         <tr>
             <th colspan="2">
-                <em><strong>Internal Notes</strong>: Notes about the canned reply.&nbsp;</em>
+                <em><strong>Internal Notes</strong>: Notes about the canned response.&nbsp;</em>
             </th>
         </tr>
         <tr>
@@ -110,7 +111,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 </table>
  <?php if ($canned && $canned->getFilters()) { ?>
     <br/>
-    <div id="msg_warning">Canned reply is in use by email filter(s): <?php
+    <div id="msg_warning">Canned response is in use by email filter(s): <?php
     echo implode(', ', $canned->getFilters()); ?></div>
  <?php } ?>
 <p style="padding-left:225px;">
diff --git a/include/staff/cannedreplies.inc.php b/include/staff/cannedresponses.inc.php
similarity index 96%
rename from include/staff/cannedreplies.inc.php
rename to include/staff/cannedresponses.inc.php
index 2f19cbd194a1ee7570fcda67eca30f295bc1d2fa..a2fe2b02531ce16d735cabee7612e35e10ebc568 100644
--- a/include/staff/cannedreplies.inc.php
+++ b/include/staff/cannedresponses.inc.php
@@ -47,10 +47,10 @@ else
 
 ?>
 <div style="width:700;padding-top:5px; float:left;">
- <h2>Canned Replies</h2>
+ <h2>Canned Responses</h2>
  </div>
 <div style="float:right;text-align:right;padding-top:5px;padding-right:5px;">
-    <b><a href="canned.php?a=add" class="Icon newReply">Add New Reply</a></b></div>
+    <b><a href="canned.php?a=add" class="Icon newReply">Add New Response</a></b></div>
 <div class="clear"></div>
 <form action="canned.php" method="POST" name="canned" onSubmit="return checkbox_checker(this,1,0);">
  <?php csrf_token(); ?>
@@ -105,7 +105,7 @@ else
             <a href="#" onclick="return reset_all(document.forms['canned'])">None</a>&nbsp;&nbsp;
             <a href="#" onclick="return toogle_all(document.forms['canned'],true)">Toggle</a>&nbsp;&nbsp;
             <?php }else{
-                echo 'No premade replies';
+                echo 'No canned responses';
             } ?>
         </td>
      </tr>
@@ -117,11 +117,11 @@ if($res && $num): //Show options..
 ?>
 <p class="centered">
     <input class="button" type="submit" name="enable" value="Enable"
-                onClick=' return confirm("Are you sure you want to ENABLE selected replies?");'>
+                onClick=' return confirm("Are you sure you want to ENABLE selected responses?");'>
     <input class="button" type="submit" name="disable" value="Disable"
-                onClick=' return confirm("Are you sure you want to DISABLE selected replies?");'>
+                onClick=' return confirm("Are you sure you want to DISABLE selected responses?");'>
     <input class="button" type="submit" name="delete" value="Delete"
-                onClick=' return confirm("Are you sure you want to DELETE selected replies?");'>
+                onClick=' return confirm("Are you sure you want to DELETE selected responses?");'>
 </p>
 <?php
 endif;
diff --git a/include/staff/categories.inc.php b/include/staff/categories.inc.php
index df750fe795f680963663edd7282d0bfa66e316ef..8d966d9c2b648645146ed8dff536ad472d20c29c 100644
--- a/include/staff/categories.inc.php
+++ b/include/staff/categories.inc.php
@@ -113,7 +113,7 @@ if($res && $num): //Show options..
     <input class="button" type="submit" name="public" value="Make Public"
                 onClick=' return confirm("Are you sure you want to make selected categories PUBLIC?");'>
     <input class="button" type="submit" name="private" value="Make Internal"
-                onClick=' return confirm("Are you sure you want to make selected replies INTERNAL?");'>
+                onClick=' return confirm("Are you sure you want to make selected categories INTERNAL?");'>
     <input class="button" type="submit" name="delete" value="Delete"
                 onClick=' return confirm("Are you sure you want to DELETE selected categories - including associated FAQs?");'>
 </p>
diff --git a/include/staff/kb-categories.inc.php b/include/staff/faq-categories.inc.php
similarity index 100%
rename from include/staff/kb-categories.inc.php
rename to include/staff/faq-categories.inc.php
diff --git a/include/staff/kb-category.inc.php b/include/staff/faq-category.inc.php
similarity index 100%
rename from include/staff/kb-category.inc.php
rename to include/staff/faq-category.inc.php
diff --git a/include/staff/groups.inc.php b/include/staff/groups.inc.php
index ccb16257bf74660ae43d4a6abad2013984323221..2e994710b806bee813dc7daa4d8f89d911efbb3d 100644
--- a/include/staff/groups.inc.php
+++ b/include/staff/groups.inc.php
@@ -3,7 +3,7 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access
 
 $qstr='';
 
-$sql='SELECT grp.*,count(staff.staff_id) as users, count(dept.dept_id) as depts '
+$sql='SELECT grp.*,count(DISTINCT staff.staff_id) as users, count(DISTINCT dept.dept_id) as depts '
      .' FROM '.GROUP_TABLE.' grp '
      .' LEFT JOIN '.STAFF_TABLE.' staff ON(staff.group_id=grp.group_id) '
      .' LEFT JOIN '.GROUP_DEPT_TABLE.' dept ON(dept.group_id=grp.group_id) '
diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php
index 6c7c94211ec855b5b7c4111c7382b15f93883239..c222f745c9419eca924b1a975781791b7142e418 100644
--- a/include/staff/helptopic.inc.php
+++ b/include/staff/helptopic.inc.php
@@ -2,14 +2,15 @@
 if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
 $info=array();
 $qstr='';
-if($topic && $_REQUEST['a']!='add'){
+if($topic && $_REQUEST['a']!='add') {
     $title='Update Help Topic';
     $action='update';
     $submit_text='Save Changes';
     $info=$topic->getInfo();
     $info['id']=$topic->getId();
+    $info['pid']=$topic->getPid();
     $qstr.='&id='.$topic->getId();
-}else {
+} else {
     $title='Add New Help Topic';
     $action='create';
     $submit_text='Add Topic';
@@ -60,10 +61,34 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             </td>
             <td>
                 <input type="radio" name="ispublic" value="1" <?php echo $info['ispublic']?'checked="checked"':''; ?>>Public
-                <input type="radio" name="ispublic" value="0" <?php echo !$info['ispublic']?'checked="checked"':''; ?>>Private <em>(Internal)</em>
+                <input type="radio" name="ispublic" value="0" <?php echo !$info['ispublic']?'checked="checked"':''; ?>>Private/Internal
                 &nbsp;<span class="error">*&nbsp;</span>
             </td>
         </tr>
+        <tr>
+            <td width="180">
+                Parent Topic:
+            </td>
+            <td>
+                <select name="pid">
+                    <option value="">&mdash; Select Parent Topic &mdash;</option>
+                    <?php
+                    $sql='SELECT topic_id, topic FROM '.TOPIC_TABLE
+                        .' WHERE topic_pid=0 '
+                        .' ORDER by topic';
+                    if(($res=db_query($sql)) && db_num_rows($res)) {
+                        while(list($id, $name)=db_fetch_row($res)) {
+                            echo sprintf('<option value="%d" %s>%s</option>',
+                                    $id, (($info['pid'] && $id==$info['pid'])?'selected="selected"':'') ,$name);
+                        }
+                    }
+                    ?>
+                </select> (<em>optional</em>)
+                &nbsp;<span class="error">&nbsp;<?php echo $errors['pid']; ?></span>
+            </td>
+        </tr>
+
+        <tr><th colspan="2"><em>New ticket options</em></th></tr>
         <tr>
             <td width="180" class="required">
                 Priority:
diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php
index 9e5482ff9b1197a14aa732ee161f3ff5e392724c..da26fbc850f642004426c075e1986efe625c2e0f 100644
--- a/include/staff/helptopics.inc.php
+++ b/include/staff/helptopics.inc.php
@@ -2,12 +2,16 @@
 if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
 
 $qstr='';
-$sql='SELECT topic.*,dept.dept_name as department,priority_desc as priority '.
-     ' FROM '.TOPIC_TABLE.' topic '.
-     ' LEFT JOIN '.DEPT_TABLE.' dept ON (dept.dept_id=topic.dept_id) '.
-     ' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (pri.priority_id=topic.priority_id) ';
+$sql='SELECT topic.* '
+    .', IF(ptopic.topic_pid IS NULL, topic.topic, CONCAT_WS(" / ", ptopic.topic, topic.topic)) as name '
+    .', dept.dept_name as department '
+    .', priority_desc as priority '
+    .' FROM '.TOPIC_TABLE.' topic '
+    .' LEFT JOIN '.TOPIC_TABLE.' ptopic ON (ptopic.topic_id=topic.topic_pid) '
+    .' LEFT JOIN '.DEPT_TABLE.' dept ON (dept.dept_id=topic.dept_id) '
+    .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (pri.priority_id=topic.priority_id) ';
 $sql.=' WHERE 1';
-$sortOptions=array('name'=>'topic.topic','status'=>'topic.isactive','type'=>'topic.ispublic',
+$sortOptions=array('name'=>'name','status'=>'topic.isactive','type'=>'topic.ispublic',
                    'dept'=>'department','priority'=>'priority','updated'=>'topic.updated');
 $orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
 $sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'name';
@@ -83,7 +87,7 @@ else
                   <input type="checkbox" name="ids[]" value="<?php echo $row['topic_id']; ?>" 
                             <?php echo $sel?'checked="checked"':''; ?>  <?php echo $default?'disabled="disabled"':''; ?>
                                 onClick="highLight(this.value,this.checked);"> </td>
-                <td><a href="helptopics.php?id=<?php echo $row['topic_id']; ?>"><?php echo $row['topic']; ?></a>&nbsp;</td>
+                <td><a href="helptopics.php?id=<?php echo $row['topic_id']; ?>"><?php echo $row['name']; ?></a>&nbsp;</td>
                 <td><?php echo $row['isactive']?'Active':'<b>Disabled</b>'; ?></td>
                 <td><?php echo $row['ispublic']?'Public':'<b>Private</b>'; ?></td>
                 <td><?php echo $row['priority']; ?></td>
diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php
index ab10d7d1955c090adeef4887c319045e7190265a..5e13d943c576b53286297ca0c36865ffefceb14f 100644
--- a/include/staff/staff.inc.php
+++ b/include/staff/staff.inc.php
@@ -11,6 +11,7 @@ if($staff && $_REQUEST['a']!='add'){
     $passwd_text='To reset the password enter a new one below';
     $info=$staff->getInfo();
     $info['id']=$staff->getId();
+    $info['teams'] = $staff->getTeams();
     $qstr.='&id='.$staff->getId();
 }else {
     $title='Add New Staff';
@@ -295,6 +296,6 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 <p style="padding-left:250px;">
     <input type="submit" name="submit" value="<?php echo $submit_text; ?>">
     <input type="reset"  name="reset"  value="Reset">
-    <input type="button" name="cancel" value="Cancel" onclick='window.location.href="departments.php"'>
+    <input type="button" name="cancel" value="Cancel" onclick='window.location.href="staff.php"'>
 </p>
 </form>
diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php
index a0138118886857922da11f3a10bcb5d7bb1d1938..39093db710d6ca41cf681232ed4fa082b1278532 100644
--- a/include/staff/ticket-edit.inc.php
+++ b/include/staff/ticket-edit.inc.php
@@ -66,7 +66,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
                     <option value="API"   <?php echo ($info['source']=='API')?'selected="selected"':''; ?>>API</option>
                     <option value="Other" <?php echo ($info['source']=='Other')?'selected="selected"':''; ?>>Other</option>
                 </select>
-                &nbsp;<font class="error"><b>*</b>&nbsp;<?=$errors['source']?></font>
+                &nbsp;<font class="error"><b>*</b>&nbsp;<?php echo $errors['source']; ?></font>
             </td>
         </tr>
         <tr>
@@ -85,7 +85,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
                     }
                     ?>
                 </select>
-                &nbsp;<font class="error"><b>*</b>&nbsp;<?=$errors['topicId']?></font>
+                &nbsp;<font class="error"><b>*</b>&nbsp;<?php echo $errors['topicId']; ?></font>
             </td>
         </tr>
         <tr>
@@ -104,7 +104,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
                     }
                     ?>
                 </select>
-                &nbsp;<font class="error">*&nbsp;<?=$errors['priorityId']?></font>
+                &nbsp;<font class="error">*&nbsp;<?php echo $errors['priorityId']; ?></font>
             </td>
         </tr>
         <tr>
@@ -123,7 +123,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
                     }
                     ?>
                 </select>
-                &nbsp;<font class="error">*&nbsp;<?=$errors['slaId']?></font>
+                &nbsp;<font class="error">*&nbsp;<?php echo $errors['slaId']; ?></font>
             </td>
         </tr>
         <tr>
@@ -131,8 +131,8 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
                 Subject:
             </td>
             <td>
-                 <input type="text" name="subject" size="60" value="<?=$info['subject']?>">
-                 &nbsp;<font class="error">*&nbsp;<?=$errors['subject']?></font>
+                 <input type="text" name="subject" size="60" value="<?php echo $info['subject']; ?>">
+                 &nbsp;<font class="error">*&nbsp;<?php $errors['subject']; ?></font>
             </td>
         </tr>
         <tr>
@@ -149,7 +149,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
                     
                 echo Misc::timeDropdown($hr, $min, 'time');
                 ?>
-                &nbsp;<font class="error">&nbsp;<?=$errors['duedate']?>&nbsp;<?php echo $errors['time']; ?></font>
+                &nbsp;<font class="error">&nbsp;<?php echo $errors['duedate']; ?>&nbsp;<?php echo $errors['time']; ?></font>
                 <em>Time is based on your time zone (GMT <?php echo $thisstaff->getTZoffset(); ?>)</em>
             </td>
         </tr>
diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php
index db3aca84018b1d0744a46363243a6f111f3bfdba..1ef3a7ba52ee0925ee4166984629d6661ce861a6 100644
--- a/include/staff/ticket-open.inc.php
+++ b/include/staff/ticket-open.inc.php
@@ -30,7 +30,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             <?php 
             if($cfg->notifyONNewStaffTicket()) { ?>
                &nbsp;&nbsp;&nbsp;
-               <input type="checkbox" name="alertuser" <?php echo (!$errors || $info['alertuser'])? 'checked="checked"': ''?>>Send alert to user.
+               <input type="checkbox" name="alertuser" <?php echo (!$errors || $info['alertuser'])? 'checked="checked"': ''; ?>>Send alert to user.
             <?php 
              } ?>
             </td>
@@ -71,7 +71,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     <option value="Email" <?php echo ($info['source']=='Email')?'selected="selected"':''; ?>>Email</option>
                     <option value="Other" <?php echo ($info['source']=='Other')?'selected="selected"':''; ?>>Other</option>
                 </select>
-                &nbsp;<font class="error"><b>*</b>&nbsp;<?=$errors['source']?></font>
+                &nbsp;<font class="error"><b>*</b>&nbsp;<?php echo $errors['source']; ?></font>
             </td>
         </tr>
         <tr>
@@ -90,7 +90,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     }
                     ?>
                 </select>
-                &nbsp;<font class="error"><b>*</b>&nbsp;<?=$errors['deptId']?></font>
+                &nbsp;<font class="error"><b>*</b>&nbsp;<?php echo $errors['deptId']; ?></font>
             </td>
         </tr>
 
@@ -110,7 +110,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     }
                     ?>
                 </select>
-                &nbsp;<font class="error"><b>*</b>&nbsp;<?=$errors['topicId']?></font>
+                &nbsp;<font class="error"><b>*</b>&nbsp;<?php echo $errors['topicId']; ?></font>
             </td>
         </tr>
         <tr>
@@ -118,13 +118,13 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 Subject:
             </td>
             <td>
-                 <input type="text" name="subject" size="55" value="<?=$info['subject']?>">
-                 &nbsp;<font class="error">*&nbsp;<?=$errors['subject']?></font>
+                 <input type="text" name="subject" size="55" value="<?php echo $info['subject']; ?>">
+                 &nbsp;<font class="error">*&nbsp;<?php echo $errors['subject']; ?></font>
             </td>
         </tr>
         <tr>
             <th colspan="2">
-                <em><strong>Issue summary</strong>: Detailed summary of the reason(s) of opening the ticket. <font class="error">*&nbsp;<?=$errors['issue']?></font></em>
+                <em><strong>Issue summary</strong>: Detailed summary of the reason(s) of opening the ticket. <font class="error">*&nbsp;<?php echo $errors['issue']; ?></font></em>
             </th>
         </tr>
         <tr>
@@ -179,14 +179,14 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <div class="file_input">
                     <input type="file" class="multifile" name="attachments[]" size="30" value="" />
                 </div>
-            <?
+            <?php
             } ?>
             </td>
         </tr>
 
         <tr>
             <th colspan="2">
-                <em><strong>Internal Note</strong>: Optional internal note (recommended on assignment) <font class="error">&nbsp;<?php echo $errors['note'];?></font></em>
+                <em><strong>Internal Note</strong>: Optional internal note (recommended on assignment) <font class="error">&nbsp;<?php echo $errors['note']; ?></font></em>
             </th>
         </tr>
         <tr>
@@ -213,7 +213,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     
                 echo Misc::timeDropdown($hr, $min, 'time');
                 ?>
-                &nbsp;<font class="error">&nbsp;<?=$errors['duedate']?>&nbsp;<?php echo $errors['time']; ?></font>
+                &nbsp;<font class="error">&nbsp;<?php echo $errors['duedate']; ?> &nbsp; <?php echo $errors['time']; ?></font>
                 <em>Time is based on your time zone (GMT <?php echo $thisstaff->getTZoffset(); ?>)</em>
             </td>
         </tr>
@@ -233,7 +233,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     }
                     ?>
                 </select>
-                &nbsp;<font class="error">&nbsp;<?=$errors['priorityId']?></font>
+                &nbsp;<font class="error">&nbsp;<?php echo $errors['priorityId']; ?></font>
             </td>
         </tr>
         <?php
@@ -269,6 +269,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
         <?php
         } ?>
+
         <?php
         if($thisstaff->canCloseTickets()) { ?>
         <tr>
@@ -290,7 +291,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 ?>
                 <label><input type="radio" name="signature" value="none" checked="checked"> None</label>
                 <?php
-                if($thisstaff->getSignature()) {?>
+                if($thisstaff->getSignature()) { ?>
                     <label><input type="radio" name="signature" value="mine"
                         <?php echo ($info['signature']=='mine')?'checked="checked"':''; ?>> My signature</label>
                 <?php
diff --git a/include/upgrader/prereq.inc.php b/include/upgrader/prereq.inc.php
index d32fc328fbe3dd51759ddbaee6f58ac25d862aa2..c08c7fedcc3618ab8f9f1e368423f5cf1deaf36e 100644
--- a/include/upgrader/prereq.inc.php
+++ b/include/upgrader/prereq.inc.php
@@ -14,9 +14,9 @@ if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access D
             <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3>
             These items are necessary in order to run the latest version of osTicket.
             <ul class="progress">
-                <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>">
+                <li class="<?php echo $upgrader->check_php()?'yes':'no'; ?>">
                 PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li>
-                <li class="<? echo $upgrader->check_mysql()?'yes':'no'; ?>">
+                <li class="<?php echo $upgrader->check_mysql()?'yes':'no'; ?>">
                 MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li>
             </ul>
             <h3>Higly Recommended:</h3>
diff --git a/include/upgrader/sql/2e7531a2-d0e37dca.patch.sql b/include/upgrader/sql/2e7531a2-d0e37dca.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..8fbcd2fda8d1538d7e7b2b9a4a8032b559fc96bd
--- /dev/null
+++ b/include/upgrader/sql/2e7531a2-d0e37dca.patch.sql
@@ -0,0 +1,14 @@
+/**
+ *  Add help topic nesting support.
+ *
+ * @version 1.7-rc2 - nested help topics.
+ */
+
+-- Add help topic parent id.
+ALTER TABLE  `%TABLE_PREFIX%help_topic` 
+    ADD  `topic_pid` INT(10) UNSIGNED NOT NULL DEFAULT  '0' AFTER  `topic_id` ,
+    ADD INDEX (  `topic_pid` );
+
+-- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='d0e37dca324648f1ce2d10528a6026d4';
diff --git a/kb/faq.php b/kb/faq.php
index e0c1661c4ff62f8bc85b6c492b2eaf4467d19570..d8c1634e35e1aa625c835143e5cea925c2b0ce0e 100644
--- a/kb/faq.php
+++ b/kb/faq.php
@@ -28,7 +28,7 @@ $inc='knowledgebase.inc.php'; //FAQs landing page.
 if($faq && $faq->isPublished()) {
     $inc='faq.inc.php';
 } elseif($category && $category->isPublic() && $_REQUEST['a']!='search') {
-    $inc='kb-category.inc.php';
+    $inc='faq-category.inc.php';
 }
 require_once(CLIENTINC_DIR.'header.inc.php');
 require_once(CLIENTINC_DIR.$inc);
diff --git a/login.php b/login.php
index 823c48a030d494f2b6ae4f06bbbcf35c8de8918d..f35693fd4083401a1aea72125e8cb1cc116710c7 100644
--- a/login.php
+++ b/login.php
@@ -20,68 +20,9 @@ define('OSTCLIENTINC',TRUE); //make includes happy
 
 require_once(INCLUDE_DIR.'class.client.php');
 require_once(INCLUDE_DIR.'class.ticket.php');
-//We are ready baby
-$loginmsg='Authentication Required';
-if($_POST && (!empty($_POST['lemail']) && !empty($_POST['lticket']))):
-    $loginmsg='Authentication Required';
-    $email=trim($_POST['lemail']);
-    $ticketID=trim($_POST['lticket']);
-    //$_SESSION['_client']=array(); #Uncomment to disable login strikes.
-    
-    //Check time for last max failed login attempt strike.
-    $loginmsg='Invalid login';
-    if($_SESSION['_client']['laststrike']) {
-        if((time()-$_SESSION['_client']['laststrike'])<$cfg->getClientLoginTimeout()) {
-            $loginmsg='Excessive failed login attempts';
-            $errors['err']='You\'ve reached maximum failed login attempts allowed. Try again later or <a href="open.php">open a new ticket</a>';
-        }else{ //Timeout is over.
-            //Reset the counter for next round of attempts after the timeout.
-            $_SESSION['_client']['laststrike']=null;
-            $_SESSION['_client']['strikes']=0;
-        }
-    }
-    //See if we can fetch local ticket id associated with the ID given
-    if(!$errors && is_numeric($ticketID) && Validator::is_email($email) && ($ticket=Ticket::lookupByExtId($ticketID))) {
-        //At this point we know the ticket is valid.
-        //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? 
-        //Check the email given.
-        if($ticket->getId() && strcasecmp($ticket->getEmail(),$email)==0){
-            //valid match...create session goodies for the client.
-            $user = new ClientSession($email,$ticket->getId());
-            $_SESSION['_client']=array(); //clear.
-            $_SESSION['_client']['userID']   =$ticket->getEmail(); //Email
-            $_SESSION['_client']['key']      =$ticket->getExtId(); //Ticket ID --acts as password when used with email. See above.
-            $_SESSION['_client']['token']    =$user->getSessionToken();
-            $_SESSION['TZ_OFFSET']=$cfg->getTZoffset();
-            $_SESSION['TZ_DST']=$cfg->observeDaylightSaving();
-            //Log login info...
-            $msg=sprintf("%s/%s logged in [%s]",$ticket->getEmail(),$ticket->getExtId(),$_SERVER['REMOTE_ADDR']);
-            $ost->logDebug('User login', $msg);
-            //Redirect tickets.php
-            session_write_close();
-            session_regenerate_id();
-            @header("Location: tickets.php?id=".$ticket->getExtId());
-            require_once('tickets.php'); //Just incase. of header already sent error.
-            exit;
-        }
-    }
-    //If we get to this point we know the login failed.
-    $_SESSION['_client']['strikes']+=1;
-    if(!$errors && $_SESSION['_client']['strikes']>$cfg->getClientMaxLogins()) {
-        $loginmsg='Access Denied';
-        $errors['err']='Forgot your login info? Please <a href="open.php">open a new ticket</a>.';
-        $_SESSION['_client']['laststrike']=time();
-        $alert='Excessive login attempts by a client?'."\n".
-                'Email: '.$_POST['lemail']."\n".'Ticket#: '.$_POST['lticket']."\n".
-                'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n".
-                'Attempts #'.$_SESSION['_client']['strikes'];
-        $ost->logError('Excessive login attempts (client)', $alert, ($cfg->alertONLoginError()));
-    }elseif($_SESSION['_client']['strikes']%2==0){ //Log every other failed login attempt as a warning.
-        $alert='Email: '.$_POST['lemail']."\n".'Ticket #: '.$_POST['lticket']."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
-               "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_client']['strikes'];
-        $ost->logWarning('Failed login attempt (client)', $alert);
-    }
-endif;
+
+if ($_POST) ClientSession::tryLogin($_POST['lticket'], $_POST['lemail']);
+else ClientSession::tryLogin($_GET['t'], $_GET['e'], $_GET['a']);
 
 $nav = new UserNav();
 $nav->setActiveNav('status');
diff --git a/main.inc.php b/main.inc.php
index 6fd31bbbd8f7a72cf4fd6997d6172bd2ab20fbc6..abcbfeabdaee005bdd83abb7719ac163e0e531af 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -62,8 +62,8 @@
     /*############## Do NOT monkey with anything else beyond this point UNLESS you really know what you are doing ##############*/
 
     #Current version && schema signature (Changes from version to version)
-    define('THIS_VERSION','1.7-RC1'); //Shown on admin panel
-    define('SCHEMA_SIGNATURE','2e7531a201b5b8650dcd43681a832ebd'); //MD5 signature of the db schema. (used to trigger upgrades)
+    define('THIS_VERSION','1.7-RC2'); //Shown on admin panel
+    define('SCHEMA_SIGNATURE','d0e37dca324648f1ce2d10528a6026d4'); //MD5 signature of the db schema. (used to trigger upgrades)
 
     #load config info
     $configfile='';
diff --git a/scp/canned.php b/scp/canned.php
index 2a2252233627510e35f0f12da6f9c916751c8143..72a1680aa21b3777afc765a2f2256d2fd433782c 100644
--- a/scp/canned.php
+++ b/scp/canned.php
@@ -2,7 +2,7 @@
 /*********************************************************************
     canned.php
 
-    Canned Replies aka Premade Responses.
+    Canned Responses aka Premade Responses.
 
     Peter Rotich <peter@osticket.com>
     Copyright (c)  2006-2012 osTicket
@@ -25,15 +25,15 @@ if(!$thisstaff || !$thisstaff->canManageCannedResponses()) {
 
 $canned=null;
 if($_REQUEST['id'] && !($canned=Canned::lookup($_REQUEST['id'])))
-    $errors['err']='Unknown or invalid canned reply ID.';
+    $errors['err']='Unknown or invalid canned response ID.';
 
 if($_POST && $thisstaff->canManageCannedResponses()) {
     switch(strtolower($_POST['do'])) {
         case 'update':
             if(!$canned) {
-                $errors['err']='Unknown or invalid canned reply.';
+                $errors['err']='Unknown or invalid canned response.';
             } elseif($canned->update($_POST, $errors)) {
-                $msg='Canned reply updated successfully';
+                $msg='Canned response updated successfully';
                 //Delete removed attachments.
                 //XXX: files[] shouldn't be changed under any circumstances.
                 $keepers = $_POST['files']?$_POST['files']:array();
@@ -50,7 +50,7 @@ if($_POST && $thisstaff->canManageCannedResponses()) {
                 $canned->reload();
 
             } elseif(!$errors['err']) {
-                $errors['err']='Error updating canned reply. Try again!';
+                $errors['err']='Error updating canned response. Try again!';
             }
             break;
         case 'create':
@@ -75,22 +75,22 @@ if($_POST && $thisstaff->canManageCannedResponses()) {
                         implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
-                            $msg='Selected canned replies enabled';
+                            $msg='Selected canned responses enabled';
                         else
-                            $warn="$num of $count selected canned replies enabled";
+                            $warn="$num of $count selected canned responses enabled";
                     } else {
-                        $errors['err']='Unable to enable selected canned replies.';
+                        $errors['err']='Unable to enable selected canned responses.';
                     }
                 } elseif($_POST['disable']) {
                     $sql='UPDATE '.CANNED_TABLE.' SET isenabled=0 WHERE canned_id IN ('.
                         implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
-                            $msg='Selected canned replies disabled';
+                            $msg='Selected canned responses disabled';
                         else
-                            $warn="$num of $count selected canned replies disabled";
+                            $warn="$num of $count selected canned responses disabled";
                     } else {
-                        $errors['err']='Unable to disable selected canned replies';
+                        $errors['err']='Unable to disable selected canned responses';
                     }
                 }elseif($_POST['delete']) {
                     $i=0;
@@ -100,11 +100,11 @@ if($_POST && $thisstaff->canManageCannedResponses()) {
                     }
 
                     if($i==$count)
-                        $msg='Selected canned replies deleted successfully';
+                        $msg='Selected canned responses deleted successfully';
                     elseif($i>0)
-                        $warn="$i of $count selected canned replies deleted";
+                        $warn="$i of $count selected canned responses deleted";
                     elseif(!$errors['err'])
-                        $errors['err']='Unable to delete selected canned replies';
+                        $errors['err']='Unable to delete selected canned responses';
                     
                 } else {
                     $errors['err']='Unknown command';
@@ -117,9 +117,9 @@ if($_POST && $thisstaff->canManageCannedResponses()) {
     }
 }
 
-$page='cannedreplies.inc.php';
+$page='cannedresponses.inc.php';
 if($canned || ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'add')))
-    $page='cannedreply.inc.php';
+    $page='cannedresponse.inc.php';
 
 $nav->setTabActive('kbase');
 require(STAFFINC_DIR.'header.inc.php');
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 3c7b83e12f3fc85001b1fd451c6fcc3e586e2752..0042ed4306a406337f3a3deec2811467c06a325d 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -234,7 +234,7 @@ a.premade { background:url(../images/icons/premade_reply.gif) }
 a.newPremade { background:url(../images/icons/new_premade_reply.gif) }
 
 a.kb { background:url(../images/icons/kb.gif) }
-a.kb-categories { background:url(../images/icons/kb-categories.gif) }
+a.faq-categories { background:url(../images/icons/faq-categories.gif) }
 a.canned { background:url(../images/icons/canned.gif) }
 
 a.staff { background:url(../images/icons/list_groups.gif) }
diff --git a/scp/dashboard.php b/scp/dashboard.php
index 8756ca1ea86522eb77c8a7b8ee381f3928de27f9..3b41ccfdfc1a2f4e123c501d8b0a1088584cffb3 100644
--- a/scp/dashboard.php
+++ b/scp/dashboard.php
@@ -63,6 +63,6 @@ member.</p>
 
 <div id="table-here"></div>
 
-<?
+<?php
 include(STAFFINC_DIR.'footer.inc.php');
 ?>
diff --git a/scp/images/kb_category_bg.png b/scp/images/faq_category_bg.png
similarity index 100%
rename from scp/images/kb_category_bg.png
rename to scp/images/faq_category_bg.png
diff --git a/scp/images/icons/kb-categories.gif b/scp/images/icons/faq-categories.gif
similarity index 100%
rename from scp/images/icons/kb-categories.gif
rename to scp/images/icons/faq-categories.gif
diff --git a/scp/images/icons/kb-categories.png b/scp/images/icons/faq-categories.png
similarity index 100%
rename from scp/images/icons/kb-categories.png
rename to scp/images/icons/faq-categories.png
diff --git a/scp/kb.php b/scp/kb.php
index 0a683a05f01d8cf294b336929038a9803171ab85..65e3a66ef2930c5b01c4fd7f9ffd6b6fa0733962 100644
--- a/scp/kb.php
+++ b/scp/kb.php
@@ -19,9 +19,9 @@ $category=null;
 if($_REQUEST['cid'] && !($category=Category::lookup($_REQUEST['cid'])))
     $errors['err']='Unknown or invalid FAQ category';
 
-$inc='kb-categories.inc.php'; //KB landing page.
+$inc='faq-categories.inc.php'; //KB landing page.
 if($category && $_REQUEST['a']!='search') {
-    $inc='kb-category.inc.php';
+    $inc='faq-category.inc.php';
 }
 $nav->setTabActive('kbase');
 require_once(STAFFINC_DIR.'header.inc.php');
diff --git a/scp/tickets.php b/scp/tickets.php
index 66af215ea732a492b5f9e99cf5b0d99c16ebdb6c..8c799a2a6a02a26c4185afece329ffc5e57cdcf4 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -163,7 +163,10 @@ if($_POST && !$errors):
                 $errors['err']='Perm. Denied. You are not allowed to edit tickets';
             elseif($ticket->update($_POST,$errors)) {
                 $msg='Ticket updated successfully';
-                $_REQUEST['a'] = null;
+                $_REQUEST['a'] = null; //Clear edit action - going back to view.
+                //Check to make sure the staff STILL has access post-update (e.g dept change).
+                if(!$ticket->checkStaffAccess($thisstaff))
+                    $ticket=null;
             } elseif(!$errors['err']) {
                 $errors['err']='Unable to update the ticket. Correct the errors below and try again!';
             }
diff --git a/setup/inc/install-prereq.inc.php b/setup/inc/install-prereq.inc.php
index b07ffd996c5f231c18c7471d419d7ec62b55969b..11746eda72bb2afe44cee62eb7f3ae99e4145a15 100644
--- a/setup/inc/install-prereq.inc.php
+++ b/setup/inc/install-prereq.inc.php
@@ -14,17 +14,17 @@ if(!defined('SETUPINC')) die('Kwaheri!');
             <h3>Required: <font color="red"><?php echo $errors['prereq']; ?></font></h3>
             These items are necessary in order to install and use osTicket.
             <ul class="progress">
-                <li class="<? echo $installer->check_php()?'yes':'no'; ?>">
+                <li class="<?php echo $installer->check_php()?'yes':'no'; ?>">
                 PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li>
-                <li class="<? echo $installer->check_mysql()?'yes':'no'; ?>">
+                <li class="<?php echo $installer->check_mysql()?'yes':'no'; ?>">
                 MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li>
             </ul>
             <h3>Recommended:</h3>
             You can use osTicket without these, but you may not be able to use all features.
             <ul class="progress">
-                <li class="<? echo extension_loaded('mcrypt')?'yes':'no'; ?>">Mcrypt extension</li>
-                <li class="<? echo extension_loaded('gd')?'yes':'no'; ?>">Gdlib extension</li>
-                <li class="<? echo extension_loaded('imap')?'yes':'no'; ?>">PHP IMAP extension</li>
+                <li class="<?php echo extension_loaded('mcrypt')?'yes':'no'; ?>">Mcrypt extension</li>
+                <li class="<?php echo extension_loaded('gd')?'yes':'no'; ?>">Gdlib extension</li>
+                <li class="<?php echo extension_loaded('imap')?'yes':'no'; ?>">PHP IMAP extension</li>
             </ul>
             <div id="bar">
                 <form method="post" action="install.php">
diff --git a/setup/inc/sql/osTicket-mysql.sql b/setup/inc/sql/osTicket-mysql.sql
index 21acfcfe83efe5b52d9ba5d9b153a87a25cc7eb9..5cfba00d6538506e29e136f188610df4508551cb 100644
--- a/setup/inc/sql/osTicket-mysql.sql
+++ b/setup/inc/sql/osTicket-mysql.sql
@@ -375,6 +375,7 @@ INSERT INTO `%TABLE_PREFIX%group_dept_access` (`group_id`, `dept_id`) VALUES
 DROP TABLE IF EXISTS `%TABLE_PREFIX%help_topic`;
 CREATE TABLE `%TABLE_PREFIX%help_topic` (
   `topic_id` int(11) unsigned NOT NULL auto_increment,
+  `topic_pid` int(10) unsigned NOT NULL default '0',
   `isactive` tinyint(1) unsigned NOT NULL default '1',
   `ispublic` tinyint(1) unsigned NOT NULL default '1',
   `noautoresp` tinyint(3) unsigned NOT NULL default '0',
@@ -389,6 +390,7 @@ CREATE TABLE `%TABLE_PREFIX%help_topic` (
   `updated` datetime NOT NULL,
   PRIMARY KEY  (`topic_id`),
   UNIQUE KEY `topic` (`topic`),
+  KEY `topic_pid` (`topic_pid`),
   KEY `priority_id` (`priority_id`),
   KEY `dept_id` (`dept_id`),
   KEY `staff_id` (`staff_id`,`team_id`),
diff --git a/setup/inc/sql/osTicket-mysql.sql.md5 b/setup/inc/sql/osTicket-mysql.sql.md5
index ad088e947dfe5eac019e5860c29e776bfabe60b1..63d2ce443b0448ca776ebc37b298a3c4ff93c387 100644
--- a/setup/inc/sql/osTicket-mysql.sql.md5
+++ b/setup/inc/sql/osTicket-mysql.sql.md5
@@ -1 +1 @@
-2e7531a201b5b8650dcd43681a832ebd
+d0e37dca324648f1ce2d10528a6026d4
diff --git a/setup/setup.inc.php b/setup/setup.inc.php
index d6f54ca268c784e471dc756d228ff888763d4730..07b86c6ffa43e13338f3b1f6c176e0cee2f53316 100644
--- a/setup/setup.inc.php
+++ b/setup/setup.inc.php
@@ -15,7 +15,7 @@
 **********************************************************************/
 
 #This  version - changed on every release
-define('THIS_VERSION', '1.7-RC1');
+define('THIS_VERSION', '1.7-RC2');
 
 #inits
 error_reporting(E_ALL ^ E_NOTICE); //turn on errors??
diff --git a/setup/test/lint.php b/setup/test/lint.php
index 4566c495a247874f538fc043cd777185e17d509c..4887856182e23d3acfed19168a92dbc744f4e9e8 100644
--- a/setup/test/lint.php
+++ b/setup/test/lint.php
@@ -44,7 +44,40 @@ if (strlen($syntax_errors)) {
     echo "$syntax_errors";
     exit();
 } else {
+    echo "pass\n";
+}
+
+function line_number_for_offset($filename, $offset) {
+    $lines = file($filename);
+    $bytes = $line = 0;
+    while ($bytes < $offset) {
+        $bytes += strlen(array_shift($lines));
+        $line += 1;
+    }
+    return $line;
+}
+echo "Short open tags: ";
+$fails = array();
+foreach ($scripts as $s) {
+    $matches = array();
+    if (preg_match_all('/<\?\s*(?!php|xml).*$/m', file_get_contents($s), $matches,
+            PREG_OFFSET_CAPTURE) > 0) {
+        foreach ($matches[0] as $match)
+            $fails[] = array(
+                str_replace($root.'/', '', $s),
+                $match[0],
+                line_number_for_offset($s, $match[1]));
+    }
+}
+if (count($fails)) {
+    echo "FAIL\n";
+    echo "-------------------------------------------------------\n";
+    foreach ($fails as $f)
+        echo sprintf("In %s, line %d: %s\n", $f[0], $f[2],
+            str_replace("\n", " ", $f[1]));
     echo "\n";
+} else {
+    echo "pass\n";
 }
 
 # Run phplint across all php files