diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css
index 1c27dede5e0257f2689723b42cb822c02ba2d689..b8ca14066d9c2c2188eeb23b997675659ea893b8 100644
--- a/assets/default/css/theme.css
+++ b/assets/default/css/theme.css
@@ -476,7 +476,7 @@ body {
 #kb > li h4 a {
   font-size: 14px;
 }
-#kb li i {
+#kb > li > i {
   display: block;
   width: 32px;
   height: 32px;
diff --git a/css/thread.css b/css/thread.css
index cdf25a7200d7b0365283e88a2fe6760c66c86fa7..2001dde95a01ad6761be77a93eadd390544f494d 100644
--- a/css/thread.css
+++ b/css/thread.css
@@ -109,8 +109,8 @@
   box-sizing: border-box;
 }
 .thread-body a {
-  color: #428bca;
-  text-decoration: none;
+  color: #428bca !important;
+  text-decoration: underline;
 }
 .thread-body a:hover,
 .thread-body a:focus {
diff --git a/include/class.faq.php b/include/class.faq.php
index 3966bec589df6ecf18f8e75d6e6a33e2935d2153..4e0fe8f456d10bb198636f87afe1ed4d546e307a 100644
--- a/include/class.faq.php
+++ b/include/class.faq.php
@@ -356,13 +356,17 @@ class FAQ extends VerySimpleModel {
         return $faq;
     }
 
+    static function allPublic() {
+        return static::objects()->exclude(array(
+            'ispublished'=>self::VISIBILITY_PRIVATE,
+            'category__ispublic'=>Category::VISIBILITY_PRIVATE,
+        ));
+    }
+
     static function countPublishedFAQs() {
         static $count;
         if (!isset($count)) {
-            $count = self::objects()->filter(array(
-                'category__ispublic__gt' => 0,
-                'ispublished__gt'=> 0
-            ))->count();
+            $count = self::allPublic()->count();
         }
         return $count;
     }
diff --git a/include/class.forms.php b/include/class.forms.php
index d4041dd47cc6e41dd48f141598b081a490280105..eb5aa52ef18b77075c92bf0e5916b72f96b7e18d 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -2330,41 +2330,4 @@ class VisibilityConstraint {
     }
 }
 
-class Q {
-    const NEGATED = 0x0001;
-    const ANY =     0x0002;
-
-    var $constraints;
-    var $flags;
-    var $negated = false;
-    var $ored = false;
-
-    function __construct($filter, $flags=0) {
-        $this->constraints = $filter;
-        $this->negated = $flags & self::NEGATED;
-        $this->ored = $flags & self::ANY;
-    }
-
-    function isNegated() {
-        return $this->negated;
-    }
-
-    function isOred() {
-        return $this->ored;
-    }
-
-    function negate() {
-        $this->negated = !$this->negated;
-        return $this;
-    }
-
-    static function not(array $constraints) {
-        return new static($constraints, self::NEGATED);
-    }
-
-    static function any(array $constraints) {
-        return new static($constraints, self::ORED);
-    }
-}
-
 ?>
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 5a837b56a78d6578282fa12f4224cb80638c8f4c..807ea26819b0299bd2f630086363a969cd04f0cb 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -32,6 +32,7 @@ include_once(INCLUDE_DIR.'class.canned.php');
 require_once(INCLUDE_DIR.'class.dynamic_forms.php');
 require_once(INCLUDE_DIR.'class.user.php');
 require_once(INCLUDE_DIR.'class.collaborator.php');
+require_once(INCLUDE_DIR.'class.faq.php');
 
 
 class Ticket {
diff --git a/include/client/faq-category.inc.php b/include/client/faq-category.inc.php
index 5a17e2176b75349d231bf22a00f50c02f39d88c3..80168a07c83a0c1758da2304225e9e66b880a345 100644
--- a/include/client/faq-category.inc.php
+++ b/include/client/faq-category.inc.php
@@ -1,34 +1,64 @@
 <?php
 if(!defined('OSTCLIENTINC') || !$category || !$category->isPublic()) die('Access Denied');
 ?>
-<h1><strong><?php echo $category->getName() ?></strong></h1>
+
+<div class="row">
+<div class="span8">
+    <h1><?php echo __('Frequently Asked Questions');?></h1>
+    <h2><strong><?php echo $category->getLocalName() ?></strong></h2>
 <p>
-<?php echo Format::safe_html($category->getDescription()); ?>
+<?php echo Format::safe_html($category->getLocalDescriptionWithImages()); ?>
 </p>
 <hr>
 <?php
-$sql='SELECT faq.faq_id, question, count(attach.file_id) as attachments '
-    .' FROM '.FAQ_TABLE.' faq '
-    .' LEFT JOIN '.ATTACHMENT_TABLE.' attach
-         ON(attach.object_id=faq.faq_id AND attach.type=\'F\' AND attach.inline = 0) '
-    .' WHERE faq.ispublished=1 AND faq.category_id='.db_input($category->getId())
-    .' GROUP BY faq.faq_id '
-    .' ORDER BY question';
-if(($res=db_query($sql)) && db_num_rows($res)) {
+$faqs = FAQ::objects()
+    ->filter(array('category'=>$category))
+    ->exclude(array('ispublished'=>false))
+    ->annotate(array('has_attachments'=>Aggregate::COUNT('attachments', false,
+        array('attachments__inline'=>0))))
+    ->order_by('-ispublished', 'question');
+
+if ($faqs->exists(true)) {
     echo '
-         <h2>'.__('Frequently Asked Questions').'</h2>
+         <h2>'.__('Further Articles').'</h2>
          <div id="faq">
             <ol>';
-    while($row=db_fetch_array($res)) {
-        $attachments=$row['attachments']?'<span class="Icon file"></span>':'';
+foreach ($faqs as $F) {
+        $attachments=$F->has_attachments?'<span class="Icon file"></span>':'';
         echo sprintf('
             <li><a href="faq.php?id=%d" >%s &nbsp;%s</a></li>',
-            $row['faq_id'],Format::htmlchars($row['question']), $attachments);
+            $F->getId(),Format::htmlchars($F->question), $attachments);
     }
     echo '  </ol>
-         </div>
-         <p><a class="back" href="index.php">&laquo; '.__('Go Back').'</a></p>';
+         </div>';
 }else {
     echo '<strong>'.__('This category does not have any FAQs.').' <a href="index.php">'.__('Back To Index').'</a></strong>';
 }
 ?>
+</div>
+
+<div class="span4">
+    <div class="sidebar">
+    <div class="searchbar">
+        <form method="get" action="faq.php">
+        <input type="hidden" name="a" value="search"/>
+        <input type="text" name="q" class="search" placeholder="<?php
+            echo __('Search our knowledge base'); ?>"/>
+        <input type="submit" style="display:none" value="search"/>
+        </form>
+    </div>
+    <div class="content">
+        <section>
+            <div class="header"><?php echo __('Help Topics'); ?></div>
+<?php
+foreach (Topic::objects()
+    ->filter(array('faqs__faq__category__category_id'=>$category->getId()))
+    as $t) { ?>
+        <a href="?topicId=<?php echo urlencode($t->getId()); ?>"
+            ><?php echo $t->getFullname(); ?></a>
+<?php } ?>
+        </section>
+    </div>
+    </div>
+</div>
+</div>
diff --git a/include/client/kb-categories.inc.php b/include/client/kb-categories.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..27f41475eb61fa7f859fb5cd100a7bce6a29132a
--- /dev/null
+++ b/include/client/kb-categories.inc.php
@@ -0,0 +1,65 @@
+<div class="row">
+<div class="span8">
+<?php
+    $categories = Category::objects()
+        ->exclude(Q::any(array('ispublic'=>false, 'faqs__ispublished'=>false)))
+        ->annotate(array('faq_count'=>Aggregate::count('faqs')))
+        ->filter(array('faq_count__gt'=>0));
+    if ($categories->all()) { ?>
+        <div><?php echo __('Click on the category to browse FAQs.'); ?></div>
+        <ul id="kb">
+<?php
+        foreach ($categories as $C) { ?>
+            <li><i></i>
+            <div style="margin-left:45px">
+            <h4><?php echo sprintf('<a href="faq.php?cid=%d">%s (%d)</a>',
+                $C->getId(), Format::htmlchars($C->getLocalName()), $C->faq_count); ?></h4>
+            <div class="faded" style="margin:10px 0">
+                <?php echo Format::safe_html($C->getLocalDescriptionWithImages()); ?>
+            </div>
+<?php       foreach ($C->faqs
+                    ->exclude(array('ispublished'=>false))
+                    ->order_by('-views')->limit(5) as $F) { ?>
+                <div class="popular-faq"><i class="icon-file-alt"></i>
+                <a href="faq.php?id=<?php echo $F->getId(); ?>">
+                <?php echo $F->getLocalQuestion() ?: $F->getQuestion(); ?>
+                </a></div>
+<?php       } ?>
+            </div>
+            </li>
+<?php   } ?>
+       </ul>
+<?php
+    } else {
+        echo __('NO FAQs found');
+    }
+?>
+</div>
+<div class="span4">
+    <div class="sidebar">
+    <div class="searchbar">
+        <form method="get" action="faq.php">
+        <input type="hidden" name="a" value="search"/>
+        <select name="topicId"  style="width:100%;max-width:100%"
+            onchange="javascript:this.form.submit();">
+            <option value="">— Browse by Topic —</option>
+<?php
+$topics = Topic::objects()
+    ->annotate(array('has_faqs'=>Aggregate::COUNT('faqs')))
+    ->filter(array('has_faqs__gt'=>0));
+foreach ($topics as $T) { ?>
+        <option value="<?php echo $T->getId(); ?>"><?php echo $T->getFullName();
+            ?></option>
+<?php } ?>
+        </select>
+        </form>
+    </div>
+    <br/>
+    <div class="content">
+        <section>
+            <div class="header"><?php echo __('Other Resources'); ?></div>
+        </section>
+    </div>
+    </div>
+</div>
+</div>
diff --git a/include/client/kb-search.inc.php b/include/client/kb-search.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..ee8f51f87e4132a9923387bcc21212b50fddd794
--- /dev/null
+++ b/include/client/kb-search.inc.php
@@ -0,0 +1,58 @@
+<div class="row">
+<div class="span8">
+    <h1><?php echo __('Frequently Asked Questions');?></h1>
+    <div><strong><?php echo __('Search Results'); ?></strong></div>
+<?php
+    if ($faqs->exists(true)) {
+        echo '<div id="faq">'.sprintf(__('%d FAQs matched your search criteria.'),
+            count($faqs->all()))
+            .'<ol>';
+        foreach ($faqs as $F) {
+            echo sprintf(
+                '<li><a href="faq.php?id=%d" class="previewfaq">%s</a></li>',
+                $F->getId(), $F->getLocalQuestion(), $F->getVisibilityDescription());
+        }
+        echo '</ol></div>';
+    } else {
+        echo '<strong class="faded">'.__('The search did not match any FAQs.').'</strong>';
+    }
+?>
+</div>
+
+<div class="span4">
+    <div class="sidebar">
+    <div class="searchbar">
+        <form method="get" action="faq.php">
+        <input type="hidden" name="a" value="search"/>
+        <input type="text" name="q" class="search" placeholder="<?php
+            echo __('Search our knowledge base'); ?>"/>
+        <input type="submit" style="display:none" value="search"/>
+        </form>
+    </div>
+    <div class="content">
+        <section>
+            <div class="header"><?php echo __('Help Topics'); ?></div>
+<?php
+foreach (Topic::objects()
+    ->annotate(array('faqs_count'=>Aggregate::count('faqs')))
+    ->filter(array('faqs_count__gt'=>0))
+    as $t) { ?>
+        <div><a href="?topicId=<?php echo urlencode($t->getId()); ?>"
+            ><?php echo $t->getFullName(); ?></a></div>
+<?php } ?>
+        </section>
+        <section>
+            <div class="header"><?php echo __('Categories'); ?></div>
+<?php
+foreach (Category::objects()
+    ->annotate(array('faqs_count'=>Aggregate::count('faqs')))
+    ->filter(array('faqs_count__gt'=>0))
+    as $C) { ?>
+        <div><a href="?cid=<?php echo urlencode($C->getId()); ?>"
+            ><?php echo $C->getLocalName(); ?></a></div>
+<?php } ?>
+        </section>
+    </div>
+    </div>
+</div>
+</div>
diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php
index 4b35efdc9262bdf95422a4f971ac7df03d3320d8..fa9ba29cc185d435dabaa85daad6d1f79d28a47a 100644
--- a/include/client/knowledgebase.inc.php
+++ b/include/client/knowledgebase.inc.php
@@ -2,95 +2,33 @@
 if(!defined('OSTCLIENTINC')) die('Access Denied');
 
 ?>
-<h1><?php echo __('Frequently Asked Questions');?></h1>
-<form action="index.php" method="get" id="kb-search">
-    <input type="hidden" name="a" value="search">
-    <div>
-    <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>">
-        <input id="searchSubmit" type="submit" value="<?php echo __('Search');?>">
-    </div>
-    <div class="sidebar">
-        <select name="topicId" id="topic-id">
-            <option value="">&mdash; <?php echo __('All Help Topics');?> &mdash;</option>
-            <?php
-foreach (Topic::objects()
-        ->annotate(array('faqs_count'=>Aggregate::count('faqs')))
-        ->filter(array('faqs_count__gt'=>0))
-    as $t) {
-                echo sprintf('<option value="%d" %s>%s</option>',
-                    $t->getId(),
-                    ($_REQUEST['topicId'] && $t->getId() == $_REQUEST['topicId']?'selected="selected"':''),
-                    $t->getFullName());
-            }
-            ?>
-        </select>
-    </div>
-</form>
-<hr>
-<div>
 <?php
-if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search.
-    $sql='SELECT faq.faq_id, question '
-        .' FROM '.FAQ_TABLE.' faq '
-        .' LEFT JOIN '.FAQ_CATEGORY_TABLE.' cat ON(cat.category_id=faq.category_id) '
-        .' LEFT JOIN '.FAQ_TOPIC_TABLE.' ft ON(ft.faq_id=faq.faq_id) '
-        .' WHERE faq.ispublished=1 AND cat.ispublic=1';
+if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search
+    $faqs = FAQ::allPublic()
+        ->annotate(array(
+            'attachment_count'=>Aggregate::COUNT('attachments'),
+            'topic_count'=>Aggregate::COUNT('topics')
+        ))
+        ->order_by('question');
 
-    if($_REQUEST['cid'])
-        $sql.=' AND faq.category_id='.db_input($_REQUEST['cid']);
+    if ($_REQUEST['cid'])
+        $faqs->filter(array('category_id'=>$_REQUEST['cid']));
 
-    if($_REQUEST['topicId'])
-        $sql.=' AND ft.topic_id='.db_input($_REQUEST['topicId']);
+    if ($_REQUEST['topicId'])
+        $faqs->filter(array('topics__topic_id'=>$_REQUEST['topicId']));
 
+    if ($_REQUEST['q'])
+        $faqs->filter(Q::ANY(array(
+            'question__contains'=>$_REQUEST['q'],
+            'answer__contains'=>$_REQUEST['q'],
+            'keywords__contains'=>$_REQUEST['q'],
+            'category__name__contains'=>$_REQUEST['q'],
+            'category__description__contains'=>$_REQUEST['q'],
+        )));
 
-    if($_REQUEST['q']) {
-        $sql.=" AND (question LIKE ('%".db_input($_REQUEST['q'],false)."%')
-                 OR answer LIKE ('%".db_input($_REQUEST['q'],false)."%')
-                 OR keywords LIKE ('%".db_input($_REQUEST['q'],false)."%')
-                 OR cat.name LIKE ('%".db_input($_REQUEST['q'],false)."%')
-                 OR cat.description LIKE ('%".db_input($_REQUEST['q'],false)."%')
-                 )";
-    }
+    include CLIENTINC_DIR . 'kb-search.inc.php';
 
-    $sql.=' GROUP BY faq.faq_id ORDER BY question';
-    echo "<div><strong>".__('Search Results').'</strong></div><div class="clear"></div>';
-    if(($res=db_query($sql)) && ($num=db_num_rows($res))) {
-        echo '<div id="faq">'.sprintf(__('%d FAQs matched your search criteria.'),$num).'
-                <ol>';
-        while($row=db_fetch_array($res)) {
-            echo sprintf('
-                <li><a href="faq.php?id=%d" class="previewfaq">%s</a></li>',
-                $row['faq_id'],$row['question'],$row['ispublished']?__('Published'):__('Internal'));
-        }
-        echo '  </ol>
-             </div>';
-    } else {
-        echo '<strong class="faded">'.__('The search did not match any FAQs.').'</strong>';
-    }
 } else { //Category Listing.
-    $categories = Category::objects()
-        ->filter(array('ispublic'=>true, 'faqs__ispublished'=>true))
-        ->annotate(array('faq_count'=>Aggregate::count('faqs')))
-        ->filter(array('faq_count__gt'=>0));
-    if ($categories->all()) {
-        echo '<div>'.__('Click on the category to browse FAQs.').'</div>
-                <ul id="kb">';
-
-        foreach ($categories as $C) { ?>
-            <li><i></i>
-            <h4><?php echo sprintf('<a href="faq.php?cid=%d">%s (%d)</a>',
-                $C->getId(), Format::htmlchars($C->name), $C->faq_count); ?></h4>
-                <?php echo Format::safe_html($C->description); ?>
-<?php       foreach ($C->faqs->order_by('-view')->limit(5) as $F) { ?>
-                <div class="popular-faq"><?php echo $F->question; ?></div>
-<?php       } ?>
-            </li>
-<?php   } ?>
-       </ul>
-<?php
-    } else {
-        echo __('NO FAQs found');
-    }
+    include CLIENTINC_DIR . 'kb-categories.inc.php';
 }
 ?>
-</div>
diff --git a/include/staff/templates/faq-print.tmpl.php b/include/staff/templates/faq-print.tmpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..76842eeb37dec37a27f1695f570ecedfc93f761f
--- /dev/null
+++ b/include/staff/templates/faq-print.tmpl.php
@@ -0,0 +1,12 @@
+<div class="faq-title flush-left"><?php echo $faq->getLocalQuestion() ?>
+</div>
+
+<div class="faded"><?php echo __('Last updated');?>
+    <?php echo Format::daydatetime($faq->getUpdateDate()); ?>
+</div>
+
+<br/>
+
+<div class="thread-body bleed">
+<?php echo $faq->getLocalAnswerWithImages(); ?>
+</div>
diff --git a/include/upgrader/upgrade.inc.php b/include/upgrader/upgrade.inc.php
index c6492c65cb311e404e9fd497f817e51136f13152..8588f742eb644904593c62a68125ce8940513b5e 100644
--- a/include/upgrader/upgrade.inc.php
+++ b/include/upgrader/upgrade.inc.php
@@ -37,11 +37,13 @@ $action=$upgrader->getNextAction();
                 </form>
             </div>
     </div>
-    <div id="sidebar">
+    <div class="sidebar">
+        <div class="content">
             <h3><?php echo __('Upgrade Tips');?></h3>
             <p>1. <?php echo __('Be patient the process will take a couple of minutes.');?></p>
             <p>2. <?php echo __('If you experience any problems, you can always restore your files/database backup.');?></p>
             <p>3. <?php echo sprintf(__('We can help. Feel free to %1$s contact us %2$s for professional help.'), '<a href="http://osticket.com/support" target="_blank">', '</a>');?></p>
+        </div>
     </div>
     <div class="clear"></div>
     <div id="upgrading">
diff --git a/js/filedrop.field.js b/js/filedrop.field.js
index 4eb5d27e91ebdb78033b0e6cdab7e4d20b57f0f8..7d332b575943224a0b6b9884b2a252bdbdb98b70 100644
--- a/js/filedrop.field.js
+++ b/js/filedrop.field.js
@@ -171,7 +171,6 @@
             .hide())
           .append($('<input type="hidden"/>').attr('name', this.options.name)
             .val(file.id))
-          .append($('<div class="clear"></div>'));
       if (this.options.deletable) {
         filenode.prepend($('<span><i class="icon-trash"></i></span>')
           .addClass('trash pull-right')
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 27e0ee3b0ebc755f0a4a8036ed2ae06a791c1858..558362932a82e357388b8f753e982ffc4351fe4f 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -154,7 +154,6 @@ div#header a {
     height:26px;
     color:#555;
     text-align:center;
-    font-weight:bold;
     position:relative;
 
     border-radius:5px 5px 0 0;
@@ -170,6 +169,7 @@ div#header a {
 
 #nav .active a {
     color:#004a80;
+    font-weight:bold;
 }
 
 #nav > li + li {
@@ -242,7 +242,6 @@ div#header a {
     padding-left:24px;
     background-position:0 50%;
     background-repeat:no-repeat;
-    font-weight:normal;
 }
 
 #nav .inactive li a:hover {
@@ -2061,3 +2060,12 @@ button a:hover {
 .required {
     font-weight: bold;
 }
+.truncate {
+    width: auto;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+td.indented {
+    padding-left: 20px;
+}
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index aa5e22199d44d6063374b4895b90cb169d9b3575..b0b3e6deacdbf5d64e017cb616992209e8b5cd29 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -33,6 +33,8 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%faq` (
   `answer` text NOT NULL,
   `keywords` tinytext,
   `notes` text,
+  `views` int(10) unsigned NOT NULL default '0',
+  `score` int(10) NOT NULL default '0',
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
   PRIMARY KEY  (`faq_id`),