diff --git a/src/applications/config/check/PhabricatorDaemonsSetupCheck.php b/src/applications/config/check/PhabricatorDaemonsSetupCheck.php
index 608bac675e..df5821665c 100644
--- a/src/applications/config/check/PhabricatorDaemonsSetupCheck.php
+++ b/src/applications/config/check/PhabricatorDaemonsSetupCheck.php
@@ -1,100 +1,100 @@
 <?php
 
 final class PhabricatorDaemonsSetupCheck extends PhabricatorSetupCheck {
 
   public function getDefaultGroup() {
     return self::GROUP_IMPORTANT;
   }
 
   protected function executeChecks() {
 
     try {
       $task_daemons = id(new PhabricatorDaemonLogQuery())
         ->setViewer(PhabricatorUser::getOmnipotentUser())
         ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
         ->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))
         ->setLimit(1)
         ->execute();
 
       $no_daemons = !$task_daemons;
     } catch (Exception $ex) {
       // Just skip this warning if the query fails for some reason.
       $no_daemons = false;
     }
 
     if ($no_daemons) {
       $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd');
 
       $summary = pht(
         'You must start the daemons to send email, rebuild search indexes, '.
         'and do other background processing.');
 
       $message = pht(
         'The daemons are not running, background processing (including '.
         'sending email, rebuilding search indexes, importing commits, '.
         'cleaning up old data, and running builds) can not be performed.'.
         "\n\n".
         'Use %s to start daemons. See %s for more information.',
         phutil_tag('tt', array(), 'bin/phd start'),
         phutil_tag(
           'a',
           array(
             'href' => $doc_href,
             'target' => '_blank',
           ),
           pht('Managing Daemons with phd')));
 
       $this->newIssue('daemons.not-running')
         ->setShortName(pht('Daemons Not Running'))
         ->setName(pht('Daemons Are Not Running'))
         ->setSummary($summary)
         ->setMessage($message)
         ->addCommand('$ ./bin/phd start');
     }
 
     $expect_user = PhabricatorEnv::getEnvConfig('phd.user');
-    if (strlen($expect_user)) {
+    if (phutil_nonempty_string($expect_user)) {
 
       try {
         $all_daemons = id(new PhabricatorDaemonLogQuery())
           ->setViewer(PhabricatorUser::getOmnipotentUser())
           ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
           ->execute();
       } catch (Exception $ex) {
         // If this query fails for some reason, just skip this check.
         $all_daemons = array();
       }
 
       foreach ($all_daemons as $daemon) {
         $actual_user = $daemon->getRunningAsUser();
         if ($actual_user == $expect_user) {
           continue;
         }
 
         $summary = pht(
           'At least one daemon is currently running as the wrong user.');
 
         $message = pht(
           'A daemon is running as user %s, but daemons should be '.
           'running as %s.'.
           "\n\n".
           'Either adjust the configuration setting %s or restart the '.
           'daemons. Daemons should attempt to run as the proper user when '.
           'restarted.',
           phutil_tag('tt', array(), $actual_user),
           phutil_tag('tt', array(), $expect_user),
           phutil_tag('tt', array(), 'phd.user'));
 
         $this->newIssue('daemons.run-as-different-user')
           ->setName(pht('Daemon Running as Wrong User'))
           ->setSummary($summary)
           ->setMessage($message)
           ->addPhabricatorConfig('phd.user')
           ->addCommand('$ ./bin/phd restart');
 
         break;
       }
     }
   }
 
 }
diff --git a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php
index 76aacbe36f..cd65c9a197 100644
--- a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php
+++ b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php
@@ -1,106 +1,106 @@
 <?php
 
 /**
  * IMPORTANT: If you use this, make sure to implement
  *
  *   public function isGlobalDragAndDropUploadEnabled() {
  *     return true;
  *   }
  *
  * on the controller(s) that render this class...! This is necessary
  * to make sure Quicksand works properly with the javascript in this
  * UI.
  */
 final class PhabricatorGlobalUploadTargetView extends AphrontView {
 
   private $showIfSupportedID;
   private $hintText;
   private $viewPolicy;
   private $submitURI;
 
   public function setShowIfSupportedID($show_if_supported_id) {
     $this->showIfSupportedID = $show_if_supported_id;
     return $this;
   }
 
   public function getShowIfSupportedID() {
     return $this->showIfSupportedID;
   }
 
   public function setHintText($hint_text) {
     $this->hintText = $hint_text;
     return $this;
   }
 
   public function getHintText() {
     return $this->hintText;
   }
 
   public function setViewPolicy($view_policy) {
     $this->viewPolicy = $view_policy;
     return $this;
   }
 
   public function getViewPolicy() {
     return $this->viewPolicy;
   }
 
   public function setSubmitURI($submit_uri) {
     $this->submitURI = $submit_uri;
     return $this;
   }
 
   public function getSubmitURI() {
     return $this->submitURI;
   }
 
 
 
   public function render() {
     $viewer = $this->getViewer();
     if (!$viewer->isLoggedIn()) {
       return null;
     }
 
     $instructions_id = 'phabricator-global-drag-and-drop-upload-instructions';
 
     require_celerity_resource('global-drag-and-drop-css');
 
     $hint_text = $this->getHintText();
-    if (!strlen($hint_text)) {
+    if (!phutil_nonempty_string($hint_text)) {
       $hint_text = "\xE2\x87\xAA ".pht('Drop Files to Upload');
     }
 
     // Use the configured default view policy. Drag and drop uploads use
     // a more restrictive view policy if we don't specify a policy explicitly,
     // as the more restrictive policy is correct for most drop targets (like
     // Pholio uploads and Remarkup text areas).
 
     $view_policy = $this->getViewPolicy();
     if ($view_policy === null) {
       $view_policy = PhabricatorFile::initializeNewFile()->getViewPolicy();
     }
 
     $submit_uri = $this->getSubmitURI();
     $done_uri = '/file/query/authored/';
 
     Javelin::initBehavior('global-drag-and-drop', array(
       'ifSupported' => $this->showIfSupportedID,
       'instructions' => $instructions_id,
       'uploadURI' => '/file/dropupload/',
       'submitURI' => $submit_uri,
       'browseURI' => $done_uri,
       'viewPolicy' => $view_policy,
       'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(),
     ));
 
     return phutil_tag(
       'div',
       array(
         'id'    => $instructions_id,
         'class' => 'phabricator-global-upload-instructions',
         'style' => 'display: none;',
       ),
       $hint_text);
   }
 }
diff --git a/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php b/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php
index dbf1586366..c3ebd825db 100644
--- a/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php
+++ b/src/applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php
@@ -1,70 +1,70 @@
 <?php
 
 final class PhabricatorHomeLauncherProfileMenuItem
   extends PhabricatorProfileMenuItem {
 
   const MENUITEMKEY = 'home.launcher.menu';
 
   public function getMenuItemTypeName() {
     return pht('More Applications');
   }
 
   private function getDefaultName() {
     return pht('More Applications');
   }
 
   public function getMenuItemTypeIcon() {
     return 'fa-ellipsis-h';
   }
 
   public function canHideMenuItem(
     PhabricatorProfileMenuItemConfiguration $config) {
     return false;
   }
 
   public function canMakeDefault(
     PhabricatorProfileMenuItemConfiguration $config) {
     return false;
   }
 
   public function getDisplayName(
     PhabricatorProfileMenuItemConfiguration $config) {
     $name = $config->getMenuItemProperty('name');
 
-    if (strlen($name)) {
+    if (phutil_nonempty_string($name)) {
       return $name;
     }
 
     return $this->getDefaultName();
   }
 
   public function buildEditEngineFields(
     PhabricatorProfileMenuItemConfiguration $config) {
     return array(
       id(new PhabricatorTextEditField())
         ->setKey('name')
         ->setLabel(pht('Name'))
         ->setPlaceholder($this->getDefaultName())
         ->setValue($config->getMenuItemProperty('name')),
     );
   }
 
   protected function newMenuItemViewList(
     PhabricatorProfileMenuItemConfiguration $config) {
     $viewer = $this->getViewer();
 
     $name = $this->getDisplayName($config);
     $icon = 'fa-ellipsis-h';
     $uri = '/applications/';
 
     $item = $this->newItemView()
       ->setURI($uri)
       ->setName($name)
       ->setIcon($icon);
 
     return array(
       $item,
     );
   }
 
 }
diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php
index aedbcc787f..3845c0f127 100644
--- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php
+++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php
@@ -1,1361 +1,1361 @@
 <?php
 
 abstract class PhabricatorProfileMenuEngine extends Phobject {
 
   private $viewer;
   private $profileObject;
   private $customPHID;
   private $items;
   private $controller;
   private $navigation;
   private $editMode;
   private $pageClasses = array();
   private $showContentCrumbs = true;
 
   const ITEM_CUSTOM_DIVIDER = 'engine.divider';
   const ITEM_MANAGE = 'item.configure';
 
   const MODE_COMBINED = 'combined';
   const MODE_GLOBAL = 'global';
   const MODE_CUSTOM = 'custom';
 
   public function setViewer(PhabricatorUser $viewer) {
     $this->viewer = $viewer;
     return $this;
   }
 
   public function getViewer() {
     return $this->viewer;
   }
 
   public function setProfileObject($profile_object) {
     $this->profileObject = $profile_object;
     return $this;
   }
 
   public function getProfileObject() {
     return $this->profileObject;
   }
 
   public function setCustomPHID($custom_phid) {
     $this->customPHID = $custom_phid;
     return $this;
   }
 
   public function getCustomPHID() {
     return $this->customPHID;
   }
 
   private function getEditModeCustomPHID() {
     $mode = $this->getEditMode();
 
     switch ($mode) {
       case self::MODE_CUSTOM:
         $custom_phid = $this->getCustomPHID();
         break;
       case self::MODE_GLOBAL:
         $custom_phid = null;
         break;
     }
 
     return $custom_phid;
   }
 
   public function setController(PhabricatorController $controller) {
     $this->controller = $controller;
     return $this;
   }
 
   public function getController() {
     return $this->controller;
   }
 
   public function addContentPageClass($class) {
     $this->pageClasses[] = $class;
     return $this;
   }
 
   public function setShowContentCrumbs($show_content_crumbs) {
     $this->showContentCrumbs = $show_content_crumbs;
     return $this;
   }
 
   public function getShowContentCrumbs() {
     return $this->showContentCrumbs;
   }
 
   abstract public function getItemURI($path);
   abstract protected function isMenuEngineConfigurable();
 
   abstract protected function getBuiltinProfileItems($object);
 
   protected function getBuiltinCustomProfileItems(
     $object,
     $custom_phid) {
     return array();
   }
 
   protected function getEditMode() {
     return $this->editMode;
   }
 
   public function buildResponse() {
     $controller = $this->getController();
 
     $viewer = $controller->getViewer();
     $this->setViewer($viewer);
 
     $request = $controller->getRequest();
 
     $item_action = $request->getURIData('itemAction');
     if (!$item_action) {
       $item_action = 'view';
     }
 
     $is_view = ($item_action == 'view');
 
     // If the engine is not configurable, don't respond to any of the editing
     // or configuration routes.
     if (!$this->isMenuEngineConfigurable()) {
       if (!$is_view) {
         return new Aphront404Response();
       }
     }
 
     $item_id = $request->getURIData('itemID');
 
     // If we miss on the MenuEngine route, try the EditEngine route. This will
     // be populated while editing items.
     if (!$item_id) {
       $item_id = $request->getURIData('id');
     }
 
     $view_list = $this->newProfileMenuItemViewList();
 
     if ($is_view) {
       $selected_item = $this->selectViewItem($view_list, $item_id);
     } else {
       if (!strlen($item_id)) {
         $item_id = self::ITEM_MANAGE;
       }
       $selected_item = $this->selectEditItem($view_list, $item_id);
     }
 
     switch ($item_action) {
       case 'view':
         // If we were not able to select an item, we're still going to render
         // a page state. For example, this happens when you create a new
         // portal for the first time.
         break;
       case 'info':
       case 'hide':
       case 'default':
       case 'builtin':
         if (!$selected_item) {
           return new Aphront404Response();
         }
         break;
       case 'edit':
         if (!$request->getURIData('id')) {
           // If we continue along the "edit" pathway without an ID, we hit an
           // unrelated exception because we can not build a new menu item out
           // of thin air. For menus, new items are created via the "new"
           // action. Just catch this case and 404 early since there's currently
           // no clean way to make EditEngine aware of this.
           return new Aphront404Response();
         }
         break;
     }
 
     $navigation = $view_list->newNavigationView();
     $crumbs = $controller->buildApplicationCrumbsForEditEngine();
 
     if (!$is_view) {
       $edit_mode = null;
 
       if ($selected_item) {
         if ($selected_item->getBuiltinKey() !== self::ITEM_MANAGE) {
           if ($selected_item->getCustomPHID()) {
             $edit_mode = 'custom';
           } else {
             $edit_mode = 'global';
           }
         }
       }
 
       if ($edit_mode === null) {
         $edit_mode = $request->getURIData('itemEditMode');
       }
 
       $available_modes = $this->getViewerEditModes();
       if ($available_modes) {
         $available_modes = array_fuse($available_modes);
         if (isset($available_modes[$edit_mode])) {
           $this->editMode = $edit_mode;
         } else {
           if ($item_action != 'configure') {
             return new Aphront404Response();
           }
         }
       }
       $page_title = pht('Configure Menu');
     } else {
       if ($selected_item) {
         $page_title = $selected_item->getDisplayName();
       } else {
         $page_title = pht('Empty');
       }
     }
 
     switch ($item_action) {
       case 'view':
         if ($selected_item) {
           try {
             $content = $this->buildItemViewContent($selected_item);
           } catch (Exception $ex) {
             $content = id(new PHUIInfoView())
               ->setTitle(pht('Unable to Render Dashboard'))
               ->setErrors(array($ex->getMessage()));
           }
 
           $crumbs->addTextCrumb($selected_item->getDisplayName());
         } else {
           $content = $this->newNoContentView($this->getItems());
         }
 
         if (!$content) {
           $content = $this->newEmptyView(
             pht('Empty'),
             pht('There is nothing here.'));
         }
         break;
       case 'configure':
         $mode = $this->getEditMode();
         if (!$mode) {
           $crumbs->addTextCrumb(pht('Configure Menu'));
           $content = $this->buildMenuEditModeContent();
         } else {
           if (count($available_modes) > 1) {
             $crumbs->addTextCrumb(
               pht('Configure Menu'),
               $this->getItemURI('configure/'));
 
             switch ($mode) {
               case self::MODE_CUSTOM:
                 $crumbs->addTextCrumb(pht('Personal'));
                 break;
               case self::MODE_GLOBAL:
                 $crumbs->addTextCrumb(pht('Global'));
                 break;
             }
           } else {
             $crumbs->addTextCrumb(pht('Configure Menu'));
           }
           $edit_list = $this->loadItems($mode);
           $content = $this->buildItemConfigureContent($edit_list);
         }
         break;
       case 'reorder':
         $mode = $this->getEditMode();
         $edit_list = $this->loadItems($mode);
         $content = $this->buildItemReorderContent($edit_list);
         break;
       case 'new':
         $item_key = $request->getURIData('itemKey');
         $mode = $this->getEditMode();
         $content = $this->buildItemNewContent($item_key, $mode);
         break;
       case 'builtin':
         $content = $this->buildItemBuiltinContent($selected_item);
         break;
       case 'hide':
         $content = $this->buildItemHideContent($selected_item);
         break;
       case 'default':
         if (!$this->isMenuEnginePinnable()) {
           return new Aphront404Response();
         }
         $content = $this->buildItemDefaultContent($selected_item);
         break;
       case 'edit':
         $content = $this->buildItemEditContent();
         break;
       default:
         throw new Exception(
           pht(
             'Unsupported item action "%s".',
             $item_action));
     }
 
     if ($content instanceof AphrontResponse) {
       return $content;
     }
 
     if ($content instanceof AphrontResponseProducerInterface) {
       return $content;
     }
 
     $crumbs->setBorder(true);
 
     $page = $controller->newPage()
       ->setTitle($page_title)
       ->appendChild($content);
 
     if (!$is_view || $this->getShowContentCrumbs()) {
       $page->setCrumbs($crumbs);
     }
 
     $page->setNavigation($navigation);
 
     if ($is_view) {
       foreach ($this->pageClasses as $class) {
         $page->addClass($class);
       }
     }
 
     return $page;
   }
 
   private function getItems() {
     if ($this->items === null) {
       $this->items = $this->loadItems(self::MODE_COMBINED);
     }
 
     return $this->items;
   }
 
   private function loadItems($mode) {
     $viewer = $this->getViewer();
     $object = $this->getProfileObject();
 
     $items = $this->loadBuiltinProfileItems($mode);
 
     $query = id(new PhabricatorProfileMenuItemConfigurationQuery())
       ->setViewer($viewer)
       ->withProfilePHIDs(array($object->getPHID()));
 
     switch ($mode) {
       case self::MODE_GLOBAL:
         $query->withCustomPHIDs(array(), true);
         break;
       case self::MODE_CUSTOM:
         $query->withCustomPHIDs(array($this->getCustomPHID()), false);
         break;
       case self::MODE_COMBINED:
         $query->withCustomPHIDs(array($this->getCustomPHID()), true);
         break;
     }
 
     $stored_items = $query->execute();
 
     foreach ($stored_items as $stored_item) {
       $impl = $stored_item->getMenuItem();
       $impl->setViewer($viewer);
       $impl->setEngine($this);
     }
 
     // Merge the stored items into the builtin items. If a builtin item has
     // a stored version, replace the defaults with the stored changes.
     foreach ($stored_items as $stored_item) {
       if (!$stored_item->shouldEnableForObject($object)) {
         continue;
       }
 
       $builtin_key = $stored_item->getBuiltinKey();
       if ($builtin_key !== null) {
         // If this builtin actually exists, replace the builtin with the
         // stored configuration. Otherwise, we're just going to drop the
         // stored config: it corresponds to an out-of-date or uninstalled
         // item.
         if (isset($items[$builtin_key])) {
           $builtin_item = $items[$builtin_key];
 
           // Copy runtime properties from the builtin item to the stored item.
           $stored_item->setIsHeadItem($builtin_item->getIsHeadItem());
           $stored_item->setIsTailItem($builtin_item->getIsTailItem());
 
           $items[$builtin_key] = $stored_item;
         } else {
           continue;
         }
       } else {
         $items[] = $stored_item;
       }
     }
 
     return $this->arrangeItems($items, $mode);
   }
 
   private function loadBuiltinProfileItems($mode) {
     $object = $this->getProfileObject();
 
     switch ($mode) {
       case self::MODE_GLOBAL:
         $builtins = $this->getBuiltinProfileItems($object);
         break;
       case self::MODE_CUSTOM:
         $builtins = $this->getBuiltinCustomProfileItems(
           $object,
           $this->getCustomPHID());
         break;
       case self::MODE_COMBINED:
         $builtins = array();
         $builtins[] = $this->getBuiltinCustomProfileItems(
           $object,
           $this->getCustomPHID());
         $builtins[] = $this->getBuiltinProfileItems($object);
         $builtins = array_mergev($builtins);
         break;
     }
 
     $items = PhabricatorProfileMenuItem::getAllMenuItems();
     $viewer = $this->getViewer();
 
     $order = 1;
     $map = array();
     foreach ($builtins as $builtin) {
       $builtin_key = $builtin->getBuiltinKey();
 
       if (!$builtin_key) {
         throw new Exception(
           pht(
             'Object produced a builtin item with no builtin item key! '.
             'Builtin items must have a unique key.'));
       }
 
       if (isset($map[$builtin_key])) {
         throw new Exception(
           pht(
             'Object produced two items with the same builtin key ("%s"). '.
             'Each item must have a unique builtin key.',
             $builtin_key));
       }
 
       $item_key = $builtin->getMenuItemKey();
 
       $item = idx($items, $item_key);
       if (!$item) {
         throw new Exception(
           pht(
             'Builtin item ("%s") specifies a bad item key ("%s"); there '.
             'is no corresponding item implementation available.',
             $builtin_key,
             $item_key));
       }
 
       $item = clone $item;
       $item->setViewer($viewer);
       $item->setEngine($this);
 
       $builtin
         ->setProfilePHID($object->getPHID())
         ->attachMenuItem($item)
         ->attachProfileObject($object)
         ->setMenuItemOrder($order);
 
       if (!$builtin->shouldEnableForObject($object)) {
         continue;
       }
 
       $map[$builtin_key] = $builtin;
 
       $order++;
     }
 
     return $map;
   }
 
   private function validateNavigationMenuItem($item) {
     if (!($item instanceof PHUIListItemView)) {
       throw new Exception(
         pht(
           'Expected buildNavigationMenuItems() to return a list of '.
           'PHUIListItemView objects, but got a surprise.'));
     }
   }
 
   public function getConfigureURI() {
     $mode = $this->getEditMode();
 
     switch ($mode) {
       case self::MODE_CUSTOM:
         return $this->getItemURI('configure/custom/');
       case self::MODE_GLOBAL:
         return $this->getItemURI('configure/global/');
     }
 
     return $this->getItemURI('configure/');
   }
 
   private function buildItemReorderContent(array $items) {
     $viewer = $this->getViewer();
     $object = $this->getProfileObject();
 
     // If you're reordering global items, you need to be able to edit the
     // object the menu appears on. If you're reordering custom items, you only
     // need to be able to edit the custom object. Currently, the custom object
     // is always the viewing user's own user object.
     $custom_phid = $this->getEditModeCustomPHID();
 
     if (!$custom_phid) {
       PhabricatorPolicyFilter::requireCapability(
         $viewer,
         $object,
         PhabricatorPolicyCapability::CAN_EDIT);
     } else {
       $policy_object = id(new PhabricatorObjectQuery())
         ->setViewer($viewer)
         ->withPHIDs(array($custom_phid))
         ->executeOne();
 
       if (!$policy_object) {
         throw new Exception(
           pht(
             'Failed to load custom PHID "%s"!',
             $custom_phid));
       }
 
       PhabricatorPolicyFilter::requireCapability(
         $viewer,
         $policy_object,
         PhabricatorPolicyCapability::CAN_EDIT);
     }
 
     $controller = $this->getController();
     $request = $controller->getRequest();
 
     $request->validateCSRF();
 
     $order = $request->getStrList('order');
 
     $by_builtin = array();
     $by_id = array();
 
     foreach ($items as $key => $item) {
       $id = $item->getID();
       if ($id) {
         $by_id[$id] = $key;
         continue;
       }
 
       $builtin_key = $item->getBuiltinKey();
       if ($builtin_key) {
         $by_builtin[$builtin_key] = $key;
         continue;
       }
     }
 
     $key_order = array();
     foreach ($order as $order_item) {
       if (isset($by_id[$order_item])) {
         $key_order[] = $by_id[$order_item];
         continue;
       }
       if (isset($by_builtin[$order_item])) {
         $key_order[] = $by_builtin[$order_item];
         continue;
       }
     }
 
     $items = array_select_keys($items, $key_order) + $items;
 
     $type_order =
       PhabricatorProfileMenuItemConfigurationTransaction::TYPE_ORDER;
 
     $order = 1;
     foreach ($items as $item) {
       $xactions = array();
 
       $xactions[] = id(new PhabricatorProfileMenuItemConfigurationTransaction())
         ->setTransactionType($type_order)
         ->setNewValue($order);
 
       $editor = id(new PhabricatorProfileMenuEditor())
         ->setContentSourceFromRequest($request)
         ->setActor($viewer)
         ->setContinueOnMissingFields(true)
         ->setContinueOnNoEffect(true)
         ->applyTransactions($item, $xactions);
 
       $order++;
     }
 
     return id(new AphrontRedirectResponse())
       ->setURI($this->getConfigureURI());
   }
 
   protected function buildItemViewContent(
     PhabricatorProfileMenuItemConfiguration $item) {
     return $item->newPageContent();
   }
 
   private function getViewerEditModes() {
     $modes = array();
 
     $viewer = $this->getViewer();
 
     if ($viewer->isLoggedIn() && $this->isMenuEnginePersonalizable()) {
       $modes[] = self::MODE_CUSTOM;
     }
 
     $object = $this->getProfileObject();
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $object,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     if ($can_edit) {
       $modes[] = self::MODE_GLOBAL;
     }
 
     return $modes;
   }
 
   protected function isMenuEnginePersonalizable() {
     return true;
   }
 
   /**
    * Does this engine support pinning items?
    *
    * Personalizable menus disable pinning by default since it creates a number
    * of weird edge cases without providing many benefits for current menus.
    *
    * @return bool True if items may be pinned as default items.
    */
   public function isMenuEnginePinnable() {
     return !$this->isMenuEnginePersonalizable();
   }
 
   private function buildMenuEditModeContent() {
     $viewer = $this->getViewer();
 
     $modes = $this->getViewerEditModes();
     if (!$modes) {
       return new Aphront404Response();
     }
 
     if (count($modes) == 1) {
       $mode = head($modes);
       return id(new AphrontRedirectResponse())
         ->setURI($this->getItemURI("configure/{$mode}/"));
     }
 
     $menu = id(new PHUIObjectItemListView())
       ->setUser($viewer);
 
     $modes = array_fuse($modes);
 
     if (isset($modes['custom'])) {
       $menu->addItem(
         id(new PHUIObjectItemView())
           ->setHeader(pht('Personal Menu Items'))
           ->setHref($this->getItemURI('configure/custom/'))
           ->setImageURI($viewer->getProfileImageURI())
           ->addAttribute(pht('Edit the menu for your personal account.')));
     }
 
     if (isset($modes['global'])) {
       $icon = id(new PHUIIconView())
         ->setIcon('fa-globe')
         ->setBackground('bg-blue');
 
       $menu->addItem(
         id(new PHUIObjectItemView())
           ->setHeader(pht('Global Menu Items'))
           ->setHref($this->getItemURI('configure/global/'))
           ->setImageIcon($icon)
           ->addAttribute(pht('Edit the global default menu for all users.')));
     }
 
     $box = id(new PHUIObjectBoxView())
       ->setObjectList($menu);
 
     $header = id(new PHUIHeaderView())
       ->setHeader(pht('Manage Menu'))
       ->setHeaderIcon('fa-list');
 
     return id(new PHUITwoColumnView())
       ->setHeader($header)
       ->setFooter($box);
   }
 
   private function buildItemConfigureContent(array $items) {
     $viewer = $this->getViewer();
     $object = $this->getProfileObject();
 
     $filtered_groups = mgroup($items, 'getMenuItemKey');
     foreach ($filtered_groups as $group) {
       $first_item = head($group);
       $first_item->willGetMenuItemViewList($group);
     }
 
     // Users only need to be able to edit the object which this menu appears
     // on if they're editing global menu items. For example, users do not need
     // to be able to edit the Favorites application to add new items to the
     // Favorites menu.
     if (!$this->getCustomPHID()) {
       PhabricatorPolicyFilter::requireCapability(
         $viewer,
         $object,
         PhabricatorPolicyCapability::CAN_EDIT);
     }
 
     $list_id = celerity_generate_unique_node_id();
 
     $mode = $this->getEditMode();
 
     Javelin::initBehavior(
       'reorder-profile-menu-items',
       array(
         'listID' => $list_id,
         'orderURI' => $this->getItemURI("reorder/{$mode}/"),
       ));
 
     $list = id(new PHUIObjectItemListView())
       ->setID($list_id)
       ->setNoDataString(pht('This menu currently has no items.'));
 
     $any_draggable = false;
     foreach ($items as $item) {
       $id = $item->getID();
       $builtin_key = $item->getBuiltinKey();
 
       $can_edit = PhabricatorPolicyFilter::hasCapability(
         $viewer,
         $item,
         PhabricatorPolicyCapability::CAN_EDIT);
 
       $view = id(new PHUIObjectItemView());
 
       $name = $item->getDisplayName();
       $type = $item->getMenuItemTypeName();
       if (!strlen(trim($name))) {
         $name = pht('Untitled "%s" Item', $type);
       }
 
       $view->setHeader($name);
       $view->addAttribute($type);
 
       $icon = $item->getMenuItem()->getMenuItemTypeIcon();
       if ($icon !== null) {
         $view->setStatusIcon($icon);
       }
 
       if ($can_edit) {
         $can_move = (!$item->getIsHeadItem() && !$item->getIsTailItem());
         if ($can_move) {
           $view
             ->setGrippable(true)
             ->addSigil('profile-menu-item')
             ->setMetadata(
               array(
                 'key' => nonempty($id, $builtin_key),
               ));
           $any_draggable = true;
         } else {
           $view->setGrippable(false);
         }
 
         if ($id) {
           $default_uri = $this->getItemURI("default/{$id}/");
         } else {
           $default_uri = $this->getItemURI("default/{$builtin_key}/");
         }
 
         $default_text = null;
 
         if ($this->isMenuEnginePinnable()) {
           if ($item->isDefault()) {
             $default_icon = 'fa-thumb-tack green';
             $default_text = pht('Current Default');
           } else if ($item->canMakeDefault()) {
             $default_icon = 'fa-thumb-tack';
             $default_text = pht('Make Default');
           }
         }
 
         if ($default_text !== null) {
           $view->addAction(
             id(new PHUIListItemView())
               ->setHref($default_uri)
               ->setWorkflow(true)
               ->setName($default_text)
               ->setIcon($default_icon));
         }
 
         if ($id) {
           $view->setHref($this->getItemURI("edit/{$id}/"));
           $hide_uri = $this->getItemURI("hide/{$id}/");
         } else {
           $view->setHref($this->getItemURI("builtin/{$builtin_key}/"));
           $hide_uri = $this->getItemURI("hide/{$builtin_key}/");
         }
 
         if ($item->isDisabled()) {
           $hide_icon = 'fa-plus';
           $hide_text = pht('Enable');
         } else if ($item->getBuiltinKey() !== null) {
           $hide_icon = 'fa-times';
           $hide_text = pht('Disable');
         } else {
           $hide_icon = 'fa-times';
           $hide_text = pht('Delete');
         }
 
         $can_disable = $item->canHideMenuItem();
 
         $view->addAction(
           id(new PHUIListItemView())
             ->setHref($hide_uri)
             ->setWorkflow(true)
             ->setDisabled(!$can_disable)
             ->setName($hide_text)
             ->setIcon($hide_icon));
       }
 
       if ($item->isDisabled()) {
         $view->setDisabled(true);
       }
 
       $list->addItem($view);
     }
 
     $item_types = PhabricatorProfileMenuItem::getAllMenuItems();
     $object = $this->getProfileObject();
 
     $action_list = id(new PhabricatorActionListView())
       ->setViewer($viewer);
 
     // See T12167. This makes the "Actions" dropdown button show up in the
     // page header.
     $action_list->setID(celerity_generate_unique_node_id());
 
     $action_list->addAction(
       id(new PhabricatorActionView())
         ->setLabel(true)
         ->setName(pht('Add New Menu Item...')));
 
     foreach ($item_types as $item_type) {
       if (!$item_type->canAddToObject($object)) {
         continue;
       }
 
       $item_key = $item_type->getMenuItemKey();
       $edit_mode = $this->getEditMode();
 
       $action_list->addAction(
         id(new PhabricatorActionView())
           ->setIcon($item_type->getMenuItemTypeIcon())
           ->setName($item_type->getMenuItemTypeName())
           ->setHref($this->getItemURI("new/{$edit_mode}/{$item_key}/"))
           ->setWorkflow(true));
     }
 
     $action_list->addAction(
       id(new PhabricatorActionView())
         ->setLabel(true)
         ->setName(pht('Documentation')));
 
     $doc_link = PhabricatorEnv::getDoclink('Profile Menu User Guide');
     $doc_name = pht('Profile Menu User Guide');
 
     $action_list->addAction(
       id(new PhabricatorActionView())
         ->setIcon('fa-book')
         ->setHref($doc_link)
         ->setName($doc_name));
 
     $header = id(new PHUIHeaderView())
       ->setHeader(pht('Menu Items'))
       ->setHeaderIcon('fa-list');
 
     $list_header = id(new PHUIHeaderView())
       ->setHeader(pht('Current Menu Items'));
 
     if ($any_draggable) {
       $list_header->setSubheader(
         pht('Drag items in this list to reorder them.'));
     }
 
     $box = id(new PHUIObjectBoxView())
       ->setHeader($list_header)
       ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
       ->setObjectList($list);
 
     $curtain = id(new PHUICurtainView())
       ->setViewer($viewer)
       ->setActionList($action_list);
 
     $view = id(new PHUITwoColumnView())
       ->setHeader($header)
       ->setCurtain($curtain)
       ->setMainColumn(
         array(
           $box,
         ));
 
     return $view;
   }
 
   private function buildItemNewContent($item_key, $mode) {
     $item_types = PhabricatorProfileMenuItem::getAllMenuItems();
     $item_type = idx($item_types, $item_key);
     if (!$item_type) {
       return new Aphront404Response();
     }
 
     $object = $this->getProfileObject();
     if (!$item_type->canAddToObject($object)) {
       return new Aphront404Response();
     }
 
     $custom_phid = $this->getEditModeCustomPHID();
 
     $configuration = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
       $object,
       $item_type,
       $custom_phid);
 
     $viewer = $this->getViewer();
 
     PhabricatorPolicyFilter::requireCapability(
       $viewer,
       $configuration,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $controller = $this->getController();
 
     return id(new PhabricatorProfileMenuEditEngine())
       ->setMenuEngine($this)
       ->setProfileObject($object)
       ->setNewMenuItemConfiguration($configuration)
       ->setCustomPHID($custom_phid)
       ->setController($controller)
       ->buildResponse();
   }
 
   private function buildItemEditContent() {
     $viewer = $this->getViewer();
     $object = $this->getProfileObject();
     $controller = $this->getController();
     $custom_phid = $this->getEditModeCustomPHID();
 
     return id(new PhabricatorProfileMenuEditEngine())
       ->setMenuEngine($this)
       ->setProfileObject($object)
       ->setController($controller)
       ->setCustomPHID($custom_phid)
       ->buildResponse();
   }
 
   private function buildItemBuiltinContent(
     PhabricatorProfileMenuItemConfiguration $configuration) {
 
     // If this builtin item has already been persisted, redirect to the
     // edit page.
     $id = $configuration->getID();
     if ($id) {
       return id(new AphrontRedirectResponse())
         ->setURI($this->getItemURI("edit/{$id}/"));
     }
 
     // Otherwise, act like we're creating a new item, we're just starting
     // with the builtin template.
     $viewer = $this->getViewer();
 
     PhabricatorPolicyFilter::requireCapability(
       $viewer,
       $configuration,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $object = $this->getProfileObject();
     $controller = $this->getController();
     $custom_phid = $this->getEditModeCustomPHID();
 
     return id(new PhabricatorProfileMenuEditEngine())
       ->setIsBuiltin(true)
       ->setMenuEngine($this)
       ->setProfileObject($object)
       ->setNewMenuItemConfiguration($configuration)
       ->setController($controller)
       ->setCustomPHID($custom_phid)
       ->buildResponse();
   }
 
   private function buildItemHideContent(
     PhabricatorProfileMenuItemConfiguration $configuration) {
 
     $controller = $this->getController();
     $request = $controller->getRequest();
     $viewer = $this->getViewer();
 
     PhabricatorPolicyFilter::requireCapability(
       $viewer,
       $configuration,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     if (!$configuration->canHideMenuItem()) {
       return $controller->newDialog()
         ->setTitle(pht('Mandatory Item'))
         ->appendParagraph(
           pht('This menu item is very important, and can not be disabled.'))
         ->addCancelButton($this->getConfigureURI());
     }
 
     if ($configuration->getBuiltinKey() === null) {
       $new_value = null;
 
       $title = pht('Delete Menu Item');
       $body = pht('Delete this menu item?');
       $button = pht('Delete Menu Item');
     } else if ($configuration->isDisabled()) {
       $new_value = PhabricatorProfileMenuItemConfiguration::VISIBILITY_VISIBLE;
 
       $title = pht('Enable Menu Item');
       $body = pht(
         'Enable this menu item? It will appear in the menu again.');
       $button = pht('Enable Menu Item');
     } else {
       $new_value = PhabricatorProfileMenuItemConfiguration::VISIBILITY_DISABLED;
 
       $title = pht('Disable Menu Item');
       $body = pht(
         'Disable this menu item? It will no longer appear in the menu, but '.
         'you can re-enable it later.');
       $button = pht('Disable Menu Item');
     }
 
     $v_visibility = $configuration->getVisibility();
     if ($request->isFormPost()) {
       if ($new_value === null) {
         $configuration->delete();
       } else {
         $type_visibility =
           PhabricatorProfileMenuItemConfigurationTransaction::TYPE_VISIBILITY;
 
         $xactions = array();
 
         $xactions[] =
           id(new PhabricatorProfileMenuItemConfigurationTransaction())
             ->setTransactionType($type_visibility)
             ->setNewValue($new_value);
 
         $editor = id(new PhabricatorProfileMenuEditor())
           ->setContentSourceFromRequest($request)
           ->setActor($viewer)
           ->setContinueOnMissingFields(true)
           ->setContinueOnNoEffect(true)
           ->applyTransactions($configuration, $xactions);
       }
 
       return id(new AphrontRedirectResponse())
         ->setURI($this->getConfigureURI());
     }
 
     return $controller->newDialog()
       ->setTitle($title)
       ->appendParagraph($body)
       ->addCancelButton($this->getConfigureURI())
       ->addSubmitButton($button);
   }
 
   private function buildItemDefaultContent(
     PhabricatorProfileMenuItemConfiguration $configuration) {
 
     $controller = $this->getController();
     $request = $controller->getRequest();
     $viewer = $this->getViewer();
 
     PhabricatorPolicyFilter::requireCapability(
       $viewer,
       $configuration,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $done_uri = $this->getConfigureURI();
 
     if (!$configuration->canMakeDefault()) {
       return $controller->newDialog()
         ->setTitle(pht('Not Defaultable'))
         ->appendParagraph(
           pht(
             'This item can not be set as the default item. This is usually '.
             'because the item has no page of its own, or links to an '.
             'external page.'))
         ->addCancelButton($done_uri);
     }
 
     if ($configuration->isDefault()) {
       return $controller->newDialog()
         ->setTitle(pht('Already Default'))
         ->appendParagraph(
           pht(
             'This item is already set as the default item for this menu.'))
         ->addCancelButton($done_uri);
     }
 
     if ($request->isFormPost()) {
       $key = $configuration->getID();
       if (!$key) {
         $key = $configuration->getBuiltinKey();
       }
 
       $this->adjustDefault($key);
 
       return id(new AphrontRedirectResponse())
         ->setURI($done_uri);
     }
 
     return $controller->newDialog()
       ->setTitle(pht('Make Default'))
       ->appendParagraph(
         pht(
           'Set this item as the default for this menu? Users arriving on '.
           'this page will be shown the content of this item by default.'))
       ->addCancelButton($done_uri)
       ->addSubmitButton(pht('Make Default'));
   }
 
   protected function newItem() {
     return PhabricatorProfileMenuItemConfiguration::initializeNewBuiltin();
   }
 
   protected function newManageItem() {
     return $this->newItem()
       ->setBuiltinKey(self::ITEM_MANAGE)
       ->setMenuItemKey(PhabricatorManageProfileMenuItem::MENUITEMKEY)
       ->setIsTailItem(true);
   }
 
   protected function newDividerItem($key) {
     return $this->newItem()
       ->setBuiltinKey($key)
       ->setMenuItemKey(PhabricatorDividerProfileMenuItem::MENUITEMKEY)
       ->setIsTailItem(true);
   }
 
   public function getDefaultMenuItemConfiguration() {
     $configs = $this->getItems();
     foreach ($configs as $config) {
       if ($config->isDefault()) {
         return $config;
       }
     }
 
     return null;
   }
 
   public function adjustDefault($key) {
     $controller = $this->getController();
     $request = $controller->getRequest();
     $viewer = $request->getViewer();
 
     $items = $this->loadItems(self::MODE_COMBINED);
 
     // To adjust the default item, we first change any existing items that
     // are marked as defaults to "visible", then make the new default item
     // the default.
 
     $default = array();
     $visible = array();
 
     foreach ($items as $item) {
       $builtin_key = $item->getBuiltinKey();
       $id = $item->getID();
 
       $is_target =
         (($builtin_key !== null) && ($builtin_key === $key)) ||
         (($id !== null) && ((int)$id === (int)$key));
 
       if ($is_target) {
         if (!$item->isDefault()) {
           $default[] = $item;
         }
       } else {
         if ($item->isDefault()) {
           $visible[] = $item;
         }
       }
     }
 
     $type_visibility =
       PhabricatorProfileMenuItemConfigurationTransaction::TYPE_VISIBILITY;
 
     $v_visible = PhabricatorProfileMenuItemConfiguration::VISIBILITY_VISIBLE;
     $v_default = PhabricatorProfileMenuItemConfiguration::VISIBILITY_DEFAULT;
 
     $apply = array(
       array($v_visible, $visible),
       array($v_default, $default),
     );
 
     foreach ($apply as $group) {
       list($value, $items) = $group;
       foreach ($items as $item) {
         $xactions = array();
 
         $xactions[] =
           id(new PhabricatorProfileMenuItemConfigurationTransaction())
             ->setTransactionType($type_visibility)
             ->setNewValue($value);
 
         $editor = id(new PhabricatorProfileMenuEditor())
           ->setContentSourceFromRequest($request)
           ->setActor($viewer)
           ->setContinueOnMissingFields(true)
           ->setContinueOnNoEffect(true)
           ->applyTransactions($item, $xactions);
       }
     }
 
     return $this;
   }
 
   private function arrangeItems(array $items, $mode) {
     // Sort the items.
     $items = msortv($items, 'getSortVector');
 
     $object = $this->getProfileObject();
 
     // If we have some global items and some custom items and are in "combined"
     // mode, put a hard-coded divider item between them.
     if ($mode == self::MODE_COMBINED) {
       $list = array();
       $seen_custom = false;
       $seen_global = false;
       foreach ($items as $item) {
         if ($item->getCustomPHID()) {
           $seen_custom = true;
         } else {
           if ($seen_custom && !$seen_global) {
             $list[] = $this->newItem()
               ->setBuiltinKey(self::ITEM_CUSTOM_DIVIDER)
               ->setMenuItemKey(PhabricatorDividerProfileMenuItem::MENUITEMKEY)
               ->attachProfileObject($object)
               ->attachMenuItem(
                 new PhabricatorDividerProfileMenuItem());
           }
           $seen_global = true;
         }
         $list[] = $item;
       }
       $items = $list;
     }
 
     // Normalize keys since callers shouldn't rely on this array being
     // partially keyed.
     $items = array_values($items);
 
     return $items;
   }
 
   final protected function newEmptyView($title, $message) {
     return id(new PHUIInfoView())
       ->setTitle($title)
       ->setSeverity(PHUIInfoView::SEVERITY_NODATA)
       ->setErrors(
         array(
           $message,
         ));
   }
 
   protected function newNoContentView(array $items) {
     return $this->newEmptyView(
       pht('No Content'),
       pht('No visible menu items can render content.'));
   }
 
 
   final public function newProfileMenuItemViewList() {
     $items = $this->getItems();
 
     // Throw away disabled items: they are not allowed to build any views for
     // the menu.
     foreach ($items as $key => $item) {
       if ($item->isDisabled()) {
         unset($items[$key]);
         continue;
       }
     }
 
     // Give each item group a callback so it can load data it needs to render
     // views.
     $groups = mgroup($items, 'getMenuItemKey');
     foreach ($groups as $group) {
       $item = head($group);
       $item->willGetMenuItemViewList($group);
     }
 
     $view_list = id(new PhabricatorProfileMenuItemViewList())
       ->setProfileMenuEngine($this);
 
     foreach ($items as $item) {
       $views = $item->getMenuItemViewList();
       foreach ($views as $view) {
         $view_list->addItemView($view);
       }
     }
 
     return $view_list;
   }
 
   private function selectViewItem(
     PhabricatorProfileMenuItemViewList $view_list,
     $item_id) {
 
     // Figure out which view's content we're going to render. In most cases,
     // the URI tells us. If we don't have an identifier in the URI, we'll
     // render the default view instead.
 
     $selected_view = null;
-    if (strlen($item_id)) {
+    if (phutil_nonempty_string($item_id)) {
       $item_views = $view_list->getViewsWithItemIdentifier($item_id);
       if ($item_views) {
         $selected_view = head($item_views);
       }
     } else {
       $default_views = $view_list->getDefaultViews();
       if ($default_views) {
         $selected_view = head($default_views);
       }
     }
 
     if ($selected_view) {
       $view_list->setSelectedView($selected_view);
       $selected_item = $selected_view->getMenuItemConfiguration();
     } else {
       $selected_item = null;
     }
 
     return $selected_item;
   }
 
   private function selectEditItem(
     PhabricatorProfileMenuItemViewList $view_list,
     $item_id) {
 
     // First, try to select a visible item using the normal view selection
     // pathway. If this works, it also highlights the menu properly.
 
     if ($item_id) {
       $selected_item = $this->selectViewItem($view_list, $item_id);
       if ($selected_item) {
         return $selected_item;
       }
     }
 
     // If we didn't find an item in the view list, we may be enabling an item
     // which is currently disabled or editing an item which is not generating
     // any actual items in the menu.
 
     foreach ($this->getItems() as $item) {
       if ($item->matchesIdentifier($item_id)) {
         return $item;
       }
     }
 
     return null;
   }
 
 
 }
diff --git a/src/applications/search/engine/PhabricatorProfileMenuItemView.php b/src/applications/search/engine/PhabricatorProfileMenuItemView.php
index d947afcba6..7f0dd1d397 100644
--- a/src/applications/search/engine/PhabricatorProfileMenuItemView.php
+++ b/src/applications/search/engine/PhabricatorProfileMenuItemView.php
@@ -1,232 +1,232 @@
 <?php
 
 final class PhabricatorProfileMenuItemView
   extends Phobject {
 
   private $config;
   private $uri;
   private $name;
   private $icon;
   private $iconImage;
   private $disabled;
   private $tooltip;
   private $actions = array();
   private $counts = array();
   private $images = array();
   private $progressBars = array();
   private $isExternalLink;
   private $specialType;
 
   public function setMenuItemConfiguration(
     PhabricatorProfileMenuItemConfiguration $config) {
     $this->config = $config;
     return $this;
   }
 
   public function getMenuItemConfiguration() {
     return $this->config;
   }
 
   public function setURI($uri) {
     $this->uri = $uri;
     return $this;
   }
 
   public function getURI() {
     return $this->uri;
   }
 
   public function setName($name) {
     $this->name = $name;
     return $this;
   }
 
   public function getName() {
     return $this->name;
   }
 
   public function setIcon($icon) {
     $this->icon = $icon;
     return $this;
   }
 
   public function getIcon() {
     return $this->icon;
   }
 
   public function setIconImage($icon_image) {
     $this->iconImage = $icon_image;
     return $this;
   }
 
   public function getIconImage() {
     return $this->iconImage;
   }
 
   public function setDisabled($disabled) {
     $this->disabled = $disabled;
     return $this;
   }
 
   public function getDisabled() {
     return $this->disabled;
   }
 
   public function setTooltip($tooltip) {
     $this->tooltip = $tooltip;
     return $this;
   }
 
   public function getTooltip() {
     return $this->tooltip;
   }
 
   public function newAction($uri) {
     $this->actions[] = $uri;
     return null;
   }
 
   public function newCount($count) {
     $this->counts[] = $count;
     return null;
   }
 
   public function newProfileImage($src) {
     $this->images[] = $src;
     return null;
   }
 
   public function newProgressBar($bar) {
     $this->progressBars[] = $bar;
     return null;
   }
 
   public function setIsExternalLink($is_external) {
     $this->isExternalLink = $is_external;
     return $this;
   }
 
   public function getIsExternalLink() {
     return $this->isExternalLink;
   }
 
   public function setIsLabel($is_label) {
     return $this->setSpecialType('label');
   }
 
   public function getIsLabel() {
     return $this->isSpecialType('label');
   }
 
   public function setIsDivider($is_divider) {
     return $this->setSpecialType('divider');
   }
 
   public function getIsDivider() {
     return $this->isSpecialType('divider');
   }
 
   private function setSpecialType($type) {
     $this->specialType = $type;
     return $this;
   }
 
   private function isSpecialType($type) {
     return ($this->specialType === $type);
   }
 
   public function newListItemView() {
     $view = id(new PHUIListItemView())
       ->setName($this->getName());
 
     $uri = $this->getURI();
-    if (strlen($uri)) {
+    if (phutil_nonempty_string($uri)) {
       if ($this->getIsExternalLink()) {
         if (!PhabricatorEnv::isValidURIForLink($uri)) {
           $uri = '#';
         }
         $view->setRel('noreferrer');
       }
 
       $view->setHref($uri);
     }
 
     $icon = $this->getIcon();
     if ($icon) {
       $view->setIcon($icon);
     }
 
     $icon_image = $this->getIconImage();
     if ($icon_image) {
       $view->setProfileImage($icon_image);
     }
 
     if ($this->getDisabled()) {
       $view->setDisabled(true);
     }
 
     if ($this->getIsLabel()) {
       $view->setType(PHUIListItemView::TYPE_LABEL);
     }
 
     if ($this->getIsDivider()) {
       $view
         ->setType(PHUIListItemView::TYPE_DIVIDER)
         ->addClass('phui-divider');
     }
 
     $tooltip = $this->getTooltip();
-    if (strlen($tooltip)) {
+    if (phutil_nonempty_string($tooltip)) {
       $view->setTooltip($tooltip);
     }
 
     if ($this->images) {
       require_celerity_resource('people-picture-menu-item-css');
       foreach ($this->images as $image_src) {
         $classes = array();
         $classes[] = 'people-menu-image';
 
         if ($this->getDisabled()) {
           $classes[] = 'phui-image-disabled';
         }
 
         $image = phutil_tag(
           'img',
           array(
             'src' => $image_src,
             'class' => implode(' ', $classes),
           ));
 
         $image = phutil_tag(
           'div',
           array(
             'class' => 'people-menu-image-container',
           ),
           $image);
 
         $view->appendChild($image);
       }
     }
 
     foreach ($this->counts as $count) {
       $view->appendChild(
         phutil_tag(
           'span',
           array(
             'class' => 'phui-list-item-count',
           ),
           $count));
     }
 
     foreach ($this->actions as $action) {
       $view->setActionIcon('fa-pencil', $action);
     }
 
     foreach ($this->progressBars as $bar) {
       $view->appendChild($bar);
     }
 
     return $view;
   }
 
 }
diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
index 9d89c52ff8..717bba7c39 100644
--- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
@@ -1,250 +1,250 @@
 <?php
 
 final class PhabricatorDashboardProfileMenuItem
   extends PhabricatorProfileMenuItem {
 
   const MENUITEMKEY = 'dashboard';
 
   const FIELD_DASHBOARD = 'dashboardPHID';
 
   private $dashboard;
   private $dashboardHandle;
 
   public function getMenuItemTypeIcon() {
     return 'fa-dashboard';
   }
 
   public function getMenuItemTypeName() {
     return pht('Dashboard');
   }
 
   public function canAddToObject($object) {
     return true;
   }
 
   public function canMakeDefault(
     PhabricatorProfileMenuItemConfiguration $config) {
     return true;
   }
 
   private function attachDashboard(PhabricatorDashboard $dashboard = null) {
     $this->dashboard = $dashboard;
     return $this;
   }
 
   private function getDashboard() {
     return $this->dashboard;
   }
 
   public function getAffectedObjectPHIDs(
     PhabricatorProfileMenuItemConfiguration $config) {
     return array(
       $this->getDashboardPHID($config),
     );
   }
 
 
   public function newPageContent(
     PhabricatorProfileMenuItemConfiguration $config) {
     $viewer = $this->getViewer();
 
     $dashboard_phid = $this->getDashboardPHID($config);
 
     // Reload the dashboard to attach panels, which we need for rendering.
     $dashboard = id(new PhabricatorDashboardQuery())
       ->setViewer($viewer)
       ->withPHIDs(array($dashboard_phid))
       ->executeOne();
     if (!$dashboard) {
       return $this->newEmptyView(
         pht('Invalid Dashboard'),
         pht('This dashboard is invalid and could not be loaded.'));
     }
 
     if ($dashboard->isArchived()) {
       return $this->newEmptyView(
         pht('Archived Dashboard'),
         pht('This dashboard has been archived.'));
     }
 
     $engine = id(new PhabricatorDashboardRenderingEngine())
       ->setViewer($viewer)
       ->setDashboard($dashboard);
 
     return $engine->renderDashboard();
   }
 
   public function willGetMenuItemViewList(array $items) {
     $viewer = $this->getViewer();
     $dashboard_phids = array();
     foreach ($items as $item) {
       $dashboard_phids[] = $this->getDashboardPHID($item);
     }
 
     $dashboards = id(new PhabricatorDashboardQuery())
       ->setViewer($viewer)
       ->withPHIDs($dashboard_phids)
       ->execute();
 
     $handles = $viewer->loadHandles($dashboard_phids);
 
     $dashboards = mpull($dashboards, null, 'getPHID');
     foreach ($items as $item) {
       $dashboard_phid = $this->getDashboardPHID($item);
       $dashboard = idx($dashboards, $dashboard_phid, null);
 
       $menu_item = $item->getMenuItem();
 
       $menu_item
         ->attachDashboard($dashboard)
         ->setDashboardHandle($handles[$dashboard_phid]);
     }
   }
 
   public function getDisplayName(
     PhabricatorProfileMenuItemConfiguration $config) {
     $dashboard = $this->getDashboard();
 
     if (!$dashboard) {
       if ($this->getDashboardHandle()->getPolicyFiltered()) {
         return pht('Restricted Dashboard');
       } else {
         return pht('Invalid Dashboard');
       }
     }
 
     if ($dashboard->isArchived()) {
       return pht('Archived Dashboard');
     }
 
-    if (strlen($this->getName($config))) {
+    if (phutil_nonempty_string($this->getName($config))) {
       return $this->getName($config);
     } else {
       return $dashboard->getName();
     }
   }
 
   public function buildEditEngineFields(
     PhabricatorProfileMenuItemConfiguration $config) {
     return array(
       id(new PhabricatorDatasourceEditField())
         ->setKey(self::FIELD_DASHBOARD)
         ->setLabel(pht('Dashboard'))
         ->setIsRequired(true)
         ->setDatasource(new PhabricatorDashboardDatasource())
         ->setSingleValue($this->getDashboardPHID($config)),
       id(new PhabricatorTextEditField())
         ->setKey('name')
         ->setLabel(pht('Name'))
         ->setValue($this->getName($config)),
     );
   }
 
   private function getName(
     PhabricatorProfileMenuItemConfiguration $config) {
     return $config->getMenuItemProperty('name');
   }
 
   protected function newMenuItemViewList(
     PhabricatorProfileMenuItemConfiguration $config) {
 
     $is_disabled = true;
     $action_uri = null;
 
     $dashboard = $this->getDashboard();
     if ($dashboard) {
       if ($dashboard->isArchived()) {
         $icon = 'fa-ban';
         $name = $this->getDisplayName($config);
       } else {
         $icon = $dashboard->getIcon();
         $name = $this->getDisplayName($config);
         $is_disabled = false;
         $action_uri = $dashboard->getURI();
       }
     } else {
       $icon = 'fa-ban';
       if ($this->getDashboardHandle()->getPolicyFiltered()) {
         $name = pht('Restricted Dashboard');
       } else {
         $name = pht('Invalid Dashboard');
       }
     }
 
     $uri = $this->getItemViewURI($config);
 
     $item = $this->newItemView()
       ->setURI($uri)
       ->setName($name)
       ->setIcon($icon)
       ->setDisabled($is_disabled);
 
     if ($action_uri) {
       $item->newAction($action_uri);
     }
 
     return array(
       $item,
     );
   }
 
   public function validateTransactions(
     PhabricatorProfileMenuItemConfiguration $config,
     $field_key,
     $value,
     array $xactions) {
 
     $viewer = $this->getViewer();
     $errors = array();
 
     if ($field_key == self::FIELD_DASHBOARD) {
       if ($this->isEmptyTransaction($value, $xactions)) {
        $errors[] = $this->newRequiredError(
          pht('You must choose a dashboard.'),
          $field_key);
       }
 
       foreach ($xactions as $xaction) {
         $new = $xaction['new'];
 
         if (!$new) {
           continue;
         }
 
         if ($new === $value) {
           continue;
         }
 
         $dashboards = id(new PhabricatorDashboardQuery())
           ->setViewer($viewer)
           ->withPHIDs(array($new))
           ->execute();
         if (!$dashboards) {
           $errors[] = $this->newInvalidError(
             pht(
               'Dashboard "%s" is not a valid dashboard which you have '.
               'permission to see.',
               $new),
             $xaction['xaction']);
         }
       }
     }
 
     return $errors;
   }
 
   private function getDashboardPHID(
     PhabricatorProfileMenuItemConfiguration $config) {
     return $config->getMenuItemProperty('dashboardPHID');
   }
 
   private function getDashboardHandle() {
     return $this->dashboardHandle;
   }
 
   private function setDashboardHandle(PhabricatorObjectHandle $handle) {
     $this->dashboardHandle = $handle;
     return $this;
   }
 
 }
diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php
index 71e3d7e8a5..23d5ad3f30 100644
--- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php
@@ -1,177 +1,177 @@
 <?php
 
 final class PhabricatorEditEngineProfileMenuItem
   extends PhabricatorProfileMenuItem {
 
   const MENUITEMKEY = 'editengine';
 
   const FIELD_FORM = 'formKey';
 
   private $form;
 
   public function getMenuItemTypeIcon() {
     return 'fa-plus';
   }
 
   public function getMenuItemTypeName() {
     return pht('Form');
   }
 
   public function canAddToObject($object) {
     return true;
   }
 
   public function attachForm($form) {
     $this->form = $form;
     return $this;
   }
 
   public function getForm() {
     $form = $this->form;
     if (!$form) {
       return null;
     }
     return $form;
   }
 
   public function willGetMenuItemViewList(array $items) {
     $viewer = $this->getViewer();
     $engines = PhabricatorEditEngine::getAllEditEngines();
     $engine_keys = array_keys($engines);
     $forms = id(new PhabricatorEditEngineConfigurationQuery())
       ->setViewer($viewer)
       ->withEngineKeys($engine_keys)
       ->withIsDisabled(false)
       ->execute();
     $form_engines = mgroup($forms, 'getEngineKey');
     $form_ids = $forms;
 
     $builtin_map = array();
     foreach ($form_engines as $engine_key => $form_engine) {
       $builtin_map[$engine_key] = mpull($form_engine, null, 'getBuiltinKey');
     }
 
     foreach ($items as $item) {
       $key = $item->getMenuItemProperty('formKey');
       list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey($key);
 
       if (is_numeric($form_key)) {
         $form = idx($form_ids, $form_key, null);
         $item->getMenuItem()->attachForm($form);
       } else if (isset($builtin_map[$engine_key][$form_key])) {
         $form = $builtin_map[$engine_key][$form_key];
         $item->getMenuItem()->attachForm($form);
       }
     }
   }
 
   public function getDisplayName(
     PhabricatorProfileMenuItemConfiguration $config) {
     $form = $this->getForm();
     if (!$form) {
       return pht('(Restricted/Invalid Form)');
     }
-    if (strlen($this->getName($config))) {
+    if (phutil_nonempty_string($this->getName($config))) {
       return $this->getName($config);
     } else {
       return $form->getName();
     }
   }
 
   public function buildEditEngineFields(
     PhabricatorProfileMenuItemConfiguration $config) {
     return array(
       id(new PhabricatorDatasourceEditField())
         ->setKey(self::FIELD_FORM)
         ->setLabel(pht('Form'))
         ->setIsRequired(true)
         ->setDatasource(new PhabricatorEditEngineDatasource())
         ->setSingleValue($config->getMenuItemProperty('formKey')),
       id(new PhabricatorTextEditField())
         ->setKey('name')
         ->setLabel(pht('Name'))
         ->setValue($this->getName($config)),
     );
   }
 
   private function getName(
     PhabricatorProfileMenuItemConfiguration $config) {
     return $config->getMenuItemProperty('name');
   }
 
   protected function newMenuItemViewList(
     PhabricatorProfileMenuItemConfiguration $config) {
 
     $form = $this->getForm();
     if (!$form) {
       return array();
     }
 
     $icon = $form->getIcon();
     $name = $this->getDisplayName($config);
 
     $uri = $form->getCreateURI();
     if ($uri === null) {
       return array();
     }
 
     $item = $this->newItemView()
       ->setURI($uri)
       ->setName($name)
       ->setIcon($icon);
 
     return array(
       $item,
     );
   }
 
   public function validateTransactions(
     PhabricatorProfileMenuItemConfiguration $config,
     $field_key,
     $value,
     array $xactions) {
 
     $viewer = $this->getViewer();
     $errors = array();
 
     if ($field_key == self::FIELD_FORM) {
       if ($this->isEmptyTransaction($value, $xactions)) {
        $errors[] = $this->newRequiredError(
          pht('You must choose a form.'),
          $field_key);
       }
 
       foreach ($xactions as $xaction) {
         $new = $xaction['new'];
 
         if (!$new) {
           continue;
         }
 
         if ($new === $value) {
           continue;
         }
 
         list($engine_key, $form_key) = PhabricatorEditEngine::splitFullKey(
           $new);
 
         $forms = id(new PhabricatorEditEngineConfigurationQuery())
           ->setViewer($viewer)
           ->withEngineKeys(array($engine_key))
           ->withIdentifiers(array($form_key))
           ->execute();
         if (!$forms) {
           $errors[] = $this->newInvalidError(
             pht(
               'Form "%s" is not a valid form which you have permission to '.
               'see.',
               $new),
             $xaction['xaction']);
         }
       }
     }
 
     return $errors;
   }
 
 }
diff --git a/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php
index 89ac4a5633..83c3133705 100644
--- a/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorManageProfileMenuItem.php
@@ -1,76 +1,76 @@
 <?php
 
 final class PhabricatorManageProfileMenuItem
   extends PhabricatorProfileMenuItem {
 
   const MENUITEMKEY = 'menu.manage';
 
   public function getMenuItemTypeName() {
     return pht('Manage Menu');
   }
 
   private function getDefaultName() {
     return pht('Edit Menu');
   }
 
   public function getMenuItemTypeIcon() {
     return 'fa-pencil';
   }
 
   public function canHideMenuItem(
     PhabricatorProfileMenuItemConfiguration $config) {
     return false;
   }
 
   public function canMakeDefault(
     PhabricatorProfileMenuItemConfiguration $config) {
     return false;
   }
 
   public function getDisplayName(
     PhabricatorProfileMenuItemConfiguration $config) {
     $name = $config->getMenuItemProperty('name');
 
-    if (strlen($name)) {
+    if (phutil_nonempty_string($name)) {
       return $name;
     }
 
     return $this->getDefaultName();
   }
 
   public function buildEditEngineFields(
     PhabricatorProfileMenuItemConfiguration $config) {
     return array(
       id(new PhabricatorTextEditField())
         ->setKey('name')
         ->setLabel(pht('Name'))
         ->setPlaceholder($this->getDefaultName())
         ->setValue($config->getMenuItemProperty('name')),
     );
   }
 
   protected function newMenuItemViewList(
     PhabricatorProfileMenuItemConfiguration $config) {
     $viewer = $this->getViewer();
 
     if (!$viewer->isLoggedIn()) {
       return array();
     }
 
     $engine = $this->getEngine();
     $uri = $engine->getItemURI('configure/');
 
     $name = $this->getDisplayName($config);
     $icon = 'fa-pencil';
 
     $item = $this->newItemView()
       ->setURI($uri)
       ->setName($name)
       ->setIcon($icon);
 
     return array(
       $item,
     );
   }
 
 }
diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php
index 6f6ce56cad..17ce1db8bb 100644
--- a/src/view/page/PhabricatorStandardPageView.php
+++ b/src/view/page/PhabricatorStandardPageView.php
@@ -1,914 +1,914 @@
 <?php
 
 /**
  * This is a standard Phabricator page with menus, Javelin, DarkConsole, and
  * basic styles.
  */
 final class PhabricatorStandardPageView extends PhabricatorBarePageView
   implements AphrontResponseProducerInterface {
 
   private $baseURI;
   private $applicationName;
   private $glyph;
   private $menuContent;
   private $showChrome = true;
   private $classes = array();
   private $disableConsole;
   private $pageObjects = array();
   private $applicationMenu;
   private $showFooter = true;
   private $showDurableColumn = true;
   private $quicksandConfig = array();
   private $tabs;
   private $crumbs;
   private $navigation;
   private $footer;
 
   public function setShowFooter($show_footer) {
     $this->showFooter = $show_footer;
     return $this;
   }
 
   public function getShowFooter() {
     return $this->showFooter;
   }
 
   public function setApplicationName($application_name) {
     $this->applicationName = $application_name;
     return $this;
   }
 
   public function setDisableConsole($disable) {
     $this->disableConsole = $disable;
     return $this;
   }
 
   public function getApplicationName() {
     return $this->applicationName;
   }
 
   public function setBaseURI($base_uri) {
     $this->baseURI = $base_uri;
     return $this;
   }
 
   public function getBaseURI() {
     return $this->baseURI;
   }
 
   public function setShowChrome($show_chrome) {
     $this->showChrome = $show_chrome;
     return $this;
   }
 
   public function getShowChrome() {
     return $this->showChrome;
   }
 
   public function addClass($class) {
     $this->classes[] = $class;
     return $this;
   }
 
   public function setPageObjectPHIDs(array $phids) {
     $this->pageObjects = $phids;
     return $this;
   }
 
   public function setShowDurableColumn($show) {
     $this->showDurableColumn = $show;
     return $this;
   }
 
   public function getShowDurableColumn() {
     $request = $this->getRequest();
     if (!$request) {
       return false;
     }
 
     $viewer = $request->getUser();
     if (!$viewer->isLoggedIn()) {
       return false;
     }
 
     $conpherence_installed = PhabricatorApplication::isClassInstalledForViewer(
       'PhabricatorConpherenceApplication',
       $viewer);
     if (!$conpherence_installed) {
       return false;
     }
 
     if ($this->isQuicksandBlacklistURI()) {
       return false;
     }
 
     return true;
   }
 
   private function isQuicksandBlacklistURI() {
     $request = $this->getRequest();
     if (!$request) {
       return false;
     }
 
     $patterns = $this->getQuicksandURIPatternBlacklist();
     $path = $request->getRequestURI()->getPath();
     foreach ($patterns as $pattern) {
       if (preg_match('(^'.$pattern.'$)', $path)) {
         return true;
       }
     }
     return false;
   }
 
   public function getDurableColumnVisible() {
     $column_key = PhabricatorConpherenceColumnVisibleSetting::SETTINGKEY;
     return (bool)$this->getUserPreference($column_key, false);
   }
 
   public function getDurableColumnMinimize() {
     $column_key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY;
     return (bool)$this->getUserPreference($column_key, false);
   }
 
   public function addQuicksandConfig(array $config) {
     $this->quicksandConfig = $config + $this->quicksandConfig;
     return $this;
   }
 
   public function getQuicksandConfig() {
     return $this->quicksandConfig;
   }
 
   public function setCrumbs(PHUICrumbsView $crumbs) {
     $this->crumbs = $crumbs;
     return $this;
   }
 
   public function getCrumbs() {
     return $this->crumbs;
   }
 
   public function setTabs(PHUIListView $tabs) {
     $tabs->setType(PHUIListView::TABBAR_LIST);
     $tabs->addClass('phabricator-standard-page-tabs');
     $this->tabs = $tabs;
     return $this;
   }
 
   public function getTabs() {
     return $this->tabs;
   }
 
   public function setNavigation(AphrontSideNavFilterView $navigation) {
     $this->navigation = $navigation;
     return $this;
   }
 
   public function getNavigation() {
     return $this->navigation;
   }
 
   public function getTitle() {
     $glyph_key = PhabricatorTitleGlyphsSetting::SETTINGKEY;
     $glyph_on = PhabricatorTitleGlyphsSetting::VALUE_TITLE_GLYPHS;
     $glyph_setting = $this->getUserPreference($glyph_key, $glyph_on);
 
     $use_glyph = ($glyph_setting == $glyph_on);
 
     $title = parent::getTitle();
 
     $prefix = null;
     if ($use_glyph) {
       $prefix = $this->getGlyph();
     } else {
       $application_name = $this->getApplicationName();
       if (strlen($application_name)) {
         $prefix = '['.$application_name.']';
       }
     }
 
-    if (strlen($prefix)) {
+    if (phutil_nonempty_string($prefix)) {
       $title = $prefix.' '.$title;
     }
 
     return $title;
   }
 
 
   protected function willRenderPage() {
     $footer = $this->renderFooter();
 
     // NOTE: A cleaner solution would be to let body layout elements implement
     // some kind of "LayoutInterface" so content can be embedded inside frames,
     // but there's only really one use case for this for now.
     $children = $this->renderChildren();
     if ($children) {
       $layout = head($children);
       if ($layout instanceof PHUIFormationView) {
         $layout->setFooter($footer);
         $footer = null;
       }
     }
 
     $this->footer = $footer;
 
     parent::willRenderPage();
 
     if (!$this->getRequest()) {
       throw new Exception(
         pht(
           'You must set the %s to render a %s.',
           'Request',
           __CLASS__));
     }
 
     $console = $this->getConsole();
 
     require_celerity_resource('phabricator-core-css');
     require_celerity_resource('phabricator-zindex-css');
     require_celerity_resource('phui-button-css');
     require_celerity_resource('phui-spacing-css');
     require_celerity_resource('phui-form-css');
     require_celerity_resource('phabricator-standard-page-view');
     require_celerity_resource('conpherence-durable-column-view');
     require_celerity_resource('font-lato');
 
     Javelin::initBehavior('workflow', array());
 
     $request = $this->getRequest();
     $user = null;
     if ($request) {
       $user = $request->getUser();
     }
 
     if ($user) {
       if ($user->isUserActivated()) {
         $offset = $user->getTimeZoneOffset();
 
         $ignore_key = PhabricatorTimezoneIgnoreOffsetSetting::SETTINGKEY;
         $ignore = $user->getUserSetting($ignore_key);
 
         Javelin::initBehavior(
           'detect-timezone',
           array(
             'offset' => $offset,
             'uri' => '/settings/timezone/',
             'message' => pht(
               'Your browser timezone setting differs from the timezone '.
               'setting in your profile, click to reconcile.'),
             'ignoreKey' => $ignore_key,
             'ignore' => $ignore,
           ));
 
         if ($user->getIsAdmin()) {
           $server_https = $request->isHTTPS();
           $server_protocol = $server_https ? 'HTTPS' : 'HTTP';
           $client_protocol = $server_https ? 'HTTP' : 'HTTPS';
 
           $doc_name = 'Configuring a Preamble Script';
           $doc_href = PhabricatorEnv::getDoclink($doc_name);
 
           Javelin::initBehavior(
             'setup-check-https',
             array(
               'server_https' => $server_https,
               'doc_name' => pht('See Documentation'),
               'doc_href' => $doc_href,
               'message' => pht(
                 'This server thinks you are using %s, but your '.
                 'client is convinced that it is using %s. This is a serious '.
                 'misconfiguration with subtle, but significant, consequences.',
                 $server_protocol, $client_protocol),
             ));
         }
       }
 
       Javelin::initBehavior('lightbox-attachments');
     }
 
     Javelin::initBehavior('aphront-form-disable-on-submit');
     Javelin::initBehavior('toggle-class', array());
     Javelin::initBehavior('history-install');
     Javelin::initBehavior('phabricator-gesture');
 
     $current_token = null;
     if ($user) {
       $current_token = $user->getCSRFToken();
     }
 
     Javelin::initBehavior(
       'refresh-csrf',
       array(
         'tokenName' => AphrontRequest::getCSRFTokenName(),
         'header' => AphrontRequest::getCSRFHeaderName(),
         'viaHeader' => AphrontRequest::getViaHeaderName(),
         'current'   => $current_token,
       ));
 
     Javelin::initBehavior('device');
 
     Javelin::initBehavior(
       'high-security-warning',
       $this->getHighSecurityWarningConfig());
 
     if (PhabricatorEnv::isReadOnly()) {
       Javelin::initBehavior(
         'read-only-warning',
         array(
           'message' => PhabricatorEnv::getReadOnlyMessage(),
           'uri' => PhabricatorEnv::getReadOnlyURI(),
         ));
     }
 
     // If we aren't showing the page chrome, skip rendering DarkConsole and the
     // main menu, since they won't be visible on the page.
     if (!$this->getShowChrome()) {
       return;
     }
 
     if ($console) {
       require_celerity_resource('aphront-dark-console-css');
 
       $headers = array();
       if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
         $headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page';
       }
       if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) {
         $headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true;
       }
 
       Javelin::initBehavior(
         'dark-console',
         $this->getConsoleConfig());
     }
 
     if ($user) {
       $viewer = $user;
     } else {
       $viewer = new PhabricatorUser();
     }
 
     $menu = id(new PhabricatorMainMenuView())
       ->setUser($viewer);
 
     if ($this->getController()) {
       $menu->setController($this->getController());
     }
 
     $application_menu = $this->applicationMenu;
     if ($application_menu) {
       if ($application_menu instanceof PHUIApplicationMenuView) {
         $crumbs = $this->getCrumbs();
         if ($crumbs) {
           $application_menu->setCrumbs($crumbs);
         }
 
         $application_menu = $application_menu->buildListView();
       }
 
       $menu->setApplicationMenu($application_menu);
     }
 
 
     $this->menuContent = $menu->render();
   }
 
 
   protected function getHead() {
     $monospaced = null;
 
     $request = $this->getRequest();
     if ($request) {
       $user = $request->getUser();
       if ($user) {
         $monospaced = $user->getUserSetting(
           PhabricatorMonospacedFontSetting::SETTINGKEY);
       }
     }
 
     $response = CelerityAPI::getStaticResourceResponse();
 
     $font_css = null;
     if (!empty($monospaced)) {
       // We can't print this normally because escaping quotation marks will
       // break the CSS. Instead, filter it strictly and then mark it as safe.
       $monospaced = new PhutilSafeHTML(
         PhabricatorMonospacedFontSetting::filterMonospacedCSSRule(
           $monospaced));
 
       $font_css = hsprintf(
         '<style type="text/css">'.
         '.PhabricatorMonospaced, '.
         '.phabricator-remarkup .remarkup-code-block '.
           '.remarkup-code { font: %s !important; } '.
         '</style>',
         $monospaced);
     }
 
     return hsprintf(
       '%s%s%s',
       parent::getHead(),
       $font_css,
       $response->renderSingleResource('javelin-magical-init', 'phabricator'));
   }
 
   public function setGlyph($glyph) {
     $this->glyph = $glyph;
     return $this;
   }
 
   public function getGlyph() {
     return $this->glyph;
   }
 
   protected function willSendResponse($response) {
     $request = $this->getRequest();
     $response = parent::willSendResponse($response);
 
     $console = $request->getApplicationConfiguration()->getConsole();
 
     if ($console) {
       $response = PhutilSafeHTML::applyFunction(
         'str_replace',
         hsprintf('<darkconsole />'),
         $console->render($request),
         $response);
     }
 
     return $response;
   }
 
   protected function getBody() {
     $user = null;
     $request = $this->getRequest();
     if ($request) {
       $user = $request->getUser();
     }
 
     $header_chrome = null;
     if ($this->getShowChrome()) {
       $header_chrome = $this->menuContent;
     }
 
     $classes = array();
     $classes[] = 'main-page-frame';
     $developer_warning = null;
     if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode') &&
         DarkConsoleErrorLogPluginAPI::getErrors()) {
       $developer_warning = phutil_tag_div(
         'aphront-developer-error-callout',
         pht(
           'This page raised PHP errors. Find them in DarkConsole '.
           'or the error log.'));
     }
 
     $main_page = phutil_tag(
       'div',
       array(
         'id' => 'phabricator-standard-page',
         'class' => 'phabricator-standard-page',
       ),
       array(
         $developer_warning,
         $header_chrome,
         phutil_tag(
           'div',
           array(
             'id' => 'phabricator-standard-page-body',
             'class' => 'phabricator-standard-page-body',
           ),
           $this->renderPageBodyContent()),
       ));
 
     $durable_column = null;
     if ($this->getShowDurableColumn()) {
       $is_visible = $this->getDurableColumnVisible();
       $is_minimize = $this->getDurableColumnMinimize();
       $durable_column = id(new ConpherenceDurableColumnView())
         ->setSelectedConpherence(null)
         ->setUser($user)
         ->setQuicksandConfig($this->buildQuicksandConfig())
         ->setVisible($is_visible)
         ->setMinimize($is_minimize)
         ->setInitialLoad(true);
       if ($is_minimize) {
         $this->classes[] = 'minimize-column';
       }
     }
 
     Javelin::initBehavior('quicksand-blacklist', array(
       'patterns' => $this->getQuicksandURIPatternBlacklist(),
     ));
 
     return phutil_tag(
       'div',
       array(
         'class' => implode(' ', $classes),
         'id' => 'main-page-frame',
       ),
       array(
         $main_page,
         $durable_column,
       ));
   }
 
   private function renderPageBodyContent() {
     $console = $this->getConsole();
 
     $body = parent::getBody();
 
     $nav = $this->getNavigation();
     $tabs = $this->getTabs();
     if ($nav) {
       $crumbs = $this->getCrumbs();
       if ($crumbs) {
         $nav->setCrumbs($crumbs);
       }
       $nav->appendChild($body);
       $nav->appendFooter($this->footer);
       $content = phutil_implode_html('', array($nav->render()));
     } else {
       $content = array();
 
       $crumbs = $this->getCrumbs();
       if ($crumbs) {
         if ($this->getTabs()) {
           $crumbs->setBorder(true);
         }
         $content[] = $crumbs;
       }
 
       $tabs = $this->getTabs();
       if ($tabs) {
         $content[] = $tabs;
       }
 
       $content[] = $body;
       $content[] = $this->footer;
 
       $content = phutil_implode_html('', $content);
     }
 
     return array(
       ($console ? hsprintf('<darkconsole />') : null),
       $content,
     );
   }
 
   protected function getTail() {
     $request = $this->getRequest();
     $user = $request->getUser();
 
     $tail = array(
       parent::getTail(),
     );
 
     $response = CelerityAPI::getStaticResourceResponse();
 
     if ($request->isHTTPS()) {
       $with_protocol = 'https';
     } else {
       $with_protocol = 'http';
     }
 
     $servers = PhabricatorNotificationServerRef::getEnabledClientServers(
       $with_protocol);
 
     if ($servers) {
       if ($user && $user->isLoggedIn()) {
         // TODO: We could tell the browser about all the servers and let it
         // do random reconnects to improve reliability.
         shuffle($servers);
         $server = head($servers);
 
         $client_uri = $server->getWebsocketURI();
 
         Javelin::initBehavior(
           'aphlict-listen',
           array(
             'websocketURI' => (string)$client_uri,
           ) + $this->buildAphlictListenConfigData());
 
         CelerityAPI::getStaticResourceResponse()
           ->addContentSecurityPolicyURI('connect-src', $client_uri);
       }
     }
 
     $tail[] = $response->renderHTMLFooter($this->getFrameable());
 
     return $tail;
   }
 
   protected function getBodyClasses() {
     $classes = array();
 
     if (!$this->getShowChrome()) {
       $classes[] = 'phabricator-chromeless-page';
     }
 
     $agent = AphrontRequest::getHTTPHeader('User-Agent');
 
     // Try to guess the device resolution based on UA strings to avoid a flash
     // of incorrectly-styled content.
     $device_guess = 'device-desktop';
     if (preg_match('@iPhone|iPod|(Android.*Chrome/[.0-9]* Mobile)@', $agent)) {
       $device_guess = 'device-phone device';
     } else if (preg_match('@iPad|(Android.*Chrome/)@', $agent)) {
       $device_guess = 'device-tablet device';
     }
 
     $classes[] = $device_guess;
 
     if (preg_match('@Windows@', $agent)) {
       $classes[] = 'platform-windows';
     } else if (preg_match('@Macintosh@', $agent)) {
       $classes[] = 'platform-mac';
     } else if (preg_match('@X11@', $agent)) {
       $classes[] = 'platform-linux';
     }
 
     if ($this->getRequest()->getStr('__print__')) {
       $classes[] = 'printable';
     }
 
     if ($this->getRequest()->getStr('__aural__')) {
       $classes[] = 'audible';
     }
 
     $classes[] = 'phui-theme-'.PhabricatorEnv::getEnvConfig('ui.header-color');
     foreach ($this->classes as $class) {
       $classes[] = $class;
     }
 
     return implode(' ', $classes);
   }
 
   private function getConsole() {
     if ($this->disableConsole) {
       return null;
     }
     return $this->getRequest()->getApplicationConfiguration()->getConsole();
   }
 
   private function getConsoleConfig() {
     $user = $this->getRequest()->getUser();
 
     $headers = array();
     if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
       $headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page';
     }
     if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) {
       $headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true;
     }
 
     if ($user) {
       $setting_tab = PhabricatorDarkConsoleTabSetting::SETTINGKEY;
       $setting_visible = PhabricatorDarkConsoleVisibleSetting::SETTINGKEY;
       $tab = $user->getUserSetting($setting_tab);
       $visible = $user->getUserSetting($setting_visible);
     } else {
       $tab = null;
       $visible = true;
     }
 
     return array(
       // NOTE: We use a generic label here to prevent input reflection
       // and mitigate compression attacks like BREACH. See discussion in
       // T3684.
       'uri' => pht('Main Request'),
       'selected' => $tab,
       'visible'  => $visible,
       'headers' => $headers,
     );
   }
 
   private function getHighSecurityWarningConfig() {
     $user = $this->getRequest()->getUser();
 
     $show = false;
     if ($user->hasSession()) {
       $hisec = ($user->getSession()->getHighSecurityUntil() - time());
       if ($hisec > 0) {
         $show = true;
       }
     }
 
     return array(
       'show' => $show,
       'uri' => '/auth/session/downgrade/',
       'message' => pht(
         'Your session is in high security mode. When you '.
         'finish using it, click here to leave.'),
         );
   }
 
   private function renderFooter() {
     if (!$this->getShowChrome()) {
       return null;
     }
 
     if (!$this->getShowFooter()) {
       return null;
     }
 
     $items = PhabricatorEnv::getEnvConfig('ui.footer-items');
     if (!$items) {
       return null;
     }
 
     $foot = array();
     foreach ($items as $item) {
       $name = idx($item, 'name', pht('Unnamed Footer Item'));
 
       $href = idx($item, 'href');
       if (!PhabricatorEnv::isValidURIForLink($href)) {
         $href = null;
       }
 
       if ($href !== null) {
         $tag = 'a';
       } else {
         $tag = 'span';
       }
 
       $foot[] = phutil_tag(
         $tag,
         array(
           'href' => $href,
         ),
         $name);
     }
     $foot = phutil_implode_html(" \xC2\xB7 ", $foot);
 
     return phutil_tag(
       'div',
       array(
         'class' => 'phabricator-standard-page-footer grouped',
       ),
       $foot);
   }
 
   public function renderForQuicksand() {
     parent::willRenderPage();
     $response = $this->renderPageBodyContent();
     $response = $this->willSendResponse($response);
 
     $extra_config = $this->getQuicksandConfig();
 
     return array(
       'content' => hsprintf('%s', $response),
     ) + $this->buildQuicksandConfig()
       + $extra_config;
   }
 
   private function buildQuicksandConfig() {
     $viewer = $this->getRequest()->getUser();
     $controller = $this->getController();
 
     $dropdown_query = id(new AphlictDropdownDataQuery())
       ->setViewer($viewer);
     $dropdown_query->execute();
 
     $hisec_warning_config = $this->getHighSecurityWarningConfig();
 
     $console_config = null;
     $console = $this->getConsole();
     if ($console) {
       $console_config = $this->getConsoleConfig();
     }
 
     $upload_enabled = false;
     if ($controller) {
       $upload_enabled = $controller->isGlobalDragAndDropUploadEnabled();
     }
 
     $application_class = null;
     $application_search_icon = null;
     $application_help = null;
     $controller = $this->getController();
     if ($controller) {
       $application = $controller->getCurrentApplication();
       if ($application) {
         $application_class = get_class($application);
         if ($application->getApplicationSearchDocumentTypes()) {
           $application_search_icon = $application->getIcon();
         }
 
         $help_items = $application->getHelpMenuItems($viewer);
         if ($help_items) {
           $help_list = id(new PhabricatorActionListView())
             ->setViewer($viewer);
           foreach ($help_items as $help_item) {
             $help_list->addAction($help_item);
           }
           $application_help = $help_list->getDropdownMenuMetadata();
         }
       }
     }
 
     return array(
       'title' => $this->getTitle(),
       'bodyClasses' => $this->getBodyClasses(),
       'aphlictDropdownData' => array(
         $dropdown_query->getNotificationData(),
         $dropdown_query->getConpherenceData(),
       ),
       'globalDragAndDrop' => $upload_enabled,
       'hisecWarningConfig' => $hisec_warning_config,
       'consoleConfig' => $console_config,
       'applicationClass' => $application_class,
       'applicationSearchIcon' => $application_search_icon,
       'helpItems' => $application_help,
     ) + $this->buildAphlictListenConfigData();
   }
 
   private function buildAphlictListenConfigData() {
     $user = $this->getRequest()->getUser();
     $subscriptions = $this->pageObjects;
     $subscriptions[] = $user->getPHID();
 
     return array(
       'pageObjects'   => array_fill_keys($this->pageObjects, true),
       'subscriptions' => $subscriptions,
     );
   }
 
   private function getQuicksandURIPatternBlacklist() {
     $applications = PhabricatorApplication::getAllApplications();
 
     $blacklist = array();
     foreach ($applications as $application) {
       $blacklist[] = $application->getQuicksandURIPatternBlacklist();
     }
 
     // See T4340. Currently, Phortune and Auth both require pulling in external
     // Javascript (for Stripe card management and Recaptcha, respectively).
     // This can put us in a position where the user loads a page with a
     // restrictive Content-Security-Policy, then uses Quicksand to navigate to
     // a page which needs to load external scripts. For now, just blacklist
     // these entire applications since we aren't giving up anything
     // significant by doing so.
 
     $blacklist[] = array(
       '/phortune/.*',
       '/auth/.*',
     );
 
     return array_mergev($blacklist);
   }
 
   private function getUserPreference($key, $default = null) {
     $request = $this->getRequest();
     if (!$request) {
       return $default;
     }
 
     $user = $request->getUser();
     if (!$user) {
       return $default;
     }
 
     return $user->getUserSetting($key);
   }
 
   public function produceAphrontResponse() {
     $controller = $this->getController();
 
     $viewer = $this->getUser();
     if ($viewer && $viewer->getPHID()) {
       $object_phids = $this->pageObjects;
       foreach ($object_phids as $object_phid) {
         PhabricatorFeedStoryNotification::updateObjectNotificationViews(
           $viewer,
           $object_phid);
       }
     }
 
     if ($this->getRequest()->isQuicksand()) {
       $content = $this->renderForQuicksand();
       $response = id(new AphrontAjaxResponse())
         ->setContent($content);
     } else {
       // See T13247. Try to find some navigational menu items to create a
       // mobile navigation menu from.
       $application_menu = $controller->buildApplicationMenu();
       if (!$application_menu) {
         $navigation = $this->getNavigation();
         if ($navigation) {
           $application_menu = $navigation->getMenu();
         }
       }
       $this->applicationMenu = $application_menu;
 
       $content = $this->render();
 
       $response = id(new AphrontWebpageResponse())
         ->setContent($content)
         ->setFrameable($this->getFrameable());
     }
 
     return $response;
   }
 
 }
diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php
index 6a69c4feaa..f0b2bbbe83 100644
--- a/src/view/page/menu/PhabricatorMainMenuView.php
+++ b/src/view/page/menu/PhabricatorMainMenuView.php
@@ -1,736 +1,736 @@
 <?php
 
 final class PhabricatorMainMenuView extends AphrontView {
 
   private $controller;
   private $applicationMenu;
 
   public function setApplicationMenu(PHUIListView $application_menu) {
     $this->applicationMenu = $application_menu;
     return $this;
   }
 
   public function getApplicationMenu() {
     return $this->applicationMenu;
   }
 
   public function setController(PhabricatorController $controller) {
     $this->controller = $controller;
     return $this;
   }
 
   public function getController() {
     return $this->controller;
   }
 
   private static function getFavicons() {
     $refs = array();
 
     $refs['favicon'] = id(new PhabricatorFaviconRef())
       ->setWidth(64)
       ->setHeight(64);
 
     $refs['message_favicon'] = id(new PhabricatorFaviconRef())
       ->setWidth(64)
       ->setHeight(64)
       ->setEmblems(
         array(
           'dot-pink',
           null,
           null,
           null,
         ));
 
     id(new PhabricatorFaviconRefQuery())
       ->withRefs($refs)
       ->execute();
 
     return mpull($refs, 'getURI');
   }
 
   public function render() {
     $viewer = $this->getViewer();
 
     require_celerity_resource('phabricator-main-menu-view');
 
     $header_id = celerity_generate_unique_node_id();
     $menu_bar = array();
     $alerts = array();
     $search_button = '';
     $app_button = '';
     $aural = null;
 
     $is_full = $this->isFullSession($viewer);
 
     if ($is_full) {
       list($menu, $dropdowns, $aural) = $this->renderNotificationMenu();
       if (array_filter($menu)) {
         $alerts[] = $menu;
       }
       $menu_bar = array_merge($menu_bar, $dropdowns);
       $app_button = $this->renderApplicationMenuButton();
       $search_button = $this->renderSearchMenuButton($header_id);
     } else if (!$viewer->isLoggedIn()) {
       $app_button = $this->renderApplicationMenuButton();
       if (PhabricatorEnv::getEnvConfig('policy.allow-public')) {
         $search_button = $this->renderSearchMenuButton($header_id);
       }
     }
 
     if ($search_button) {
       $search_menu = $this->renderPhabricatorSearchMenu();
     } else {
       $search_menu = null;
     }
 
     if ($alerts) {
       $alerts = javelin_tag(
         'div',
         array(
           'class' => 'phabricator-main-menu-alerts',
           'aural' => false,
         ),
         $alerts);
     }
 
     if ($aural) {
       $aural = javelin_tag(
         'span',
         array(
           'aural' => true,
         ),
         phutil_implode_html(' ', $aural));
     }
 
     $extensions = PhabricatorMainMenuBarExtension::getAllEnabledExtensions();
     foreach ($extensions as $extension) {
       $extension
         ->setViewer($viewer)
         ->setIsFullSession($is_full);
 
       $controller = $this->getController();
       if ($controller) {
         $extension->setController($controller);
         $application = $controller->getCurrentApplication();
         if ($application) {
           $extension->setApplication($application);
         }
       }
     }
 
     if (!$is_full) {
       foreach ($extensions as $key => $extension) {
         if ($extension->shouldRequireFullSession()) {
           unset($extensions[$key]);
         }
       }
     }
 
     foreach ($extensions as $key => $extension) {
       if (!$extension->isExtensionEnabledForViewer($extension->getViewer())) {
         unset($extensions[$key]);
       }
     }
 
     $menus = array();
     foreach ($extensions as $extension) {
       foreach ($extension->buildMainMenus() as $menu) {
         $menus[] = $menu;
       }
     }
 
     // Because we display these with "float: right", reverse their order before
     // rendering them into the document so that the extension order and display
     // order are the same.
     $menus = array_reverse($menus);
 
     foreach ($menus as $menu) {
       $menu_bar[] = $menu;
     }
 
     $classes = array();
     $classes[] = 'phabricator-main-menu';
     $classes[] = 'phabricator-main-menu-background';
 
     return phutil_tag(
       'div',
       array(
         'class' => implode(' ', $classes),
         'id'    => $header_id,
       ),
       array(
         $app_button,
         $search_button,
         $this->renderPhabricatorLogo(),
         $alerts,
         $aural,
         $search_menu,
         $menu_bar,
       ));
   }
 
   private function renderSearch() {
     $viewer = $this->getViewer();
 
     $result = null;
 
     $keyboard_config = array(
       'helpURI' => '/help/keyboardshortcut/',
     );
 
     if ($viewer->isLoggedIn()) {
       $show_search = $viewer->isUserActivated();
     } else {
       $show_search = PhabricatorEnv::getEnvConfig('policy.allow-public');
     }
 
     if ($show_search) {
       $search = new PhabricatorMainMenuSearchView();
       $search->setViewer($viewer);
 
       $application = null;
       $controller = $this->getController();
       if ($controller) {
         $application = $controller->getCurrentApplication();
       }
       if ($application) {
         $search->setApplication($application);
       }
 
       $result = $search;
       $keyboard_config['searchID'] = $search->getID();
     }
 
     $keyboard_config['pht'] = array(
       '/' => pht('Give keyboard focus to the search box.'),
       '?' => pht('Show keyboard shortcut help for the current page.'),
     );
 
     Javelin::initBehavior(
       'phabricator-keyboard-shortcuts',
       $keyboard_config);
 
     if ($result) {
       $result = id(new PHUIListItemView())
         ->addClass('phabricator-main-menu-search')
         ->appendChild($result);
     }
 
     return $result;
   }
 
   public function renderApplicationMenuButton() {
     $dropdown = $this->renderApplicationMenu();
     if (!$dropdown) {
       return null;
     }
 
     return id(new PHUIButtonView())
       ->setTag('a')
       ->setHref('#')
       ->setIcon('fa-bars')
       ->addClass('phabricator-core-user-menu')
       ->addClass('phabricator-core-user-mobile-menu')
       ->setNoCSS(true)
       ->setDropdownMenu($dropdown)
       ->setAuralLabel(pht('Page Menu'));
   }
 
   private function renderApplicationMenu() {
     $viewer = $this->getViewer();
     $view = $this->getApplicationMenu();
     if ($view) {
       $items = $view->getItems();
       $view = id(new PhabricatorActionListView())
         ->setViewer($viewer);
       foreach ($items as $item) {
         $view->addAction(
           id(new PhabricatorActionView())
             ->setName($item->getName())
             ->setHref($item->getHref())
             ->setType($item->getType()));
       }
     }
     return $view;
   }
 
   public function renderSearchMenuButton($header_id) {
     $button_id = celerity_generate_unique_node_id();
     return javelin_tag(
       'a',
       array(
         'class' => 'phabricator-main-menu-search-button '.
                    'phabricator-expand-application-menu',
         'sigil' => 'jx-toggle-class',
         'meta'  => array(
           'map' => array(
             $header_id => 'phabricator-search-menu-expanded',
             $button_id => 'menu-icon-selected',
           ),
         ),
       ),
       phutil_tag(
       'span',
       array(
         'class' => 'phabricator-menu-button-icon phui-icon-view '.
                    'phui-font-fa fa-search',
         'id' => $button_id,
       ),
       ''));
   }
 
   private function renderPhabricatorSearchMenu() {
 
     $view = new PHUIListView();
     $view->addClass('phabricator-search-menu');
 
     $search = $this->renderSearch();
     if ($search) {
       $view->addMenuItem($search);
     }
 
     return $view;
   }
 
   private function renderPhabricatorLogo() {
     $custom_header = PhabricatorCustomLogoConfigType::getLogoImagePHID();
 
     $logo_style = array();
     if ($custom_header) {
       $cache = PhabricatorCaches::getImmutableCache();
       $cache_key_logo = 'ui.custom-header.logo-phid.v3.'.$custom_header;
 
       $logo_uri = $cache->getKey($cache_key_logo);
       if (!$logo_uri) {
         // NOTE: If the file policy has been changed to be restrictive, we'll
         // miss here and just show the default logo. The cache will fill later
         // when someone who can see the file loads the page. This might be a
         // little spooky, see T11982.
         $files = id(new PhabricatorFileQuery())
           ->setViewer($this->getViewer())
           ->withPHIDs(array($custom_header))
           ->execute();
         $file = head($files);
         if ($file) {
           $logo_uri = $file->getViewURI();
           $cache->setKey($cache_key_logo, $logo_uri);
         }
       }
 
       if ($logo_uri) {
         $logo_style[] = 'background-size: 40px 40px;';
         $logo_style[] = 'background-position: 0 0;';
         $logo_style[] = 'background-image: url('.$logo_uri.')';
       }
     }
 
     $logo_node = phutil_tag(
       'span',
       array(
         'class' => 'phabricator-main-menu-project-logo',
         'style' => implode(' ', $logo_style),
       ));
 
 
     $wordmark_text = PhabricatorCustomLogoConfigType::getLogoWordmark();
-    if (!strlen($wordmark_text)) {
+    if (!phutil_nonempty_string($wordmark_text)) {
       $wordmark_text = PlatformSymbols::getPlatformServerName();
     }
 
     $wordmark_node = phutil_tag(
       'span',
       array(
         'class' => 'phabricator-wordmark',
       ),
       $wordmark_text);
 
     return phutil_tag(
       'a',
       array(
         'class' => 'phabricator-main-menu-brand',
         'href'  => '/',
       ),
       array(
         javelin_tag(
           'span',
           array(
             'aural' => true,
           ),
           pht('Home')),
         $logo_node,
         $wordmark_node,
       ));
   }
 
   private function renderNotificationMenu() {
     $viewer = $this->getViewer();
 
     require_celerity_resource('phabricator-notification-css');
     require_celerity_resource('phabricator-notification-menu-css');
 
     $container_classes = array('alert-notifications');
     $aural = array();
 
     $dropdown_query = id(new AphlictDropdownDataQuery())
       ->setViewer($viewer);
     $dropdown_data = $dropdown_query->execute();
 
     $message_tag = '';
     $message_notification_dropdown = '';
     $conpherence_app = 'PhabricatorConpherenceApplication';
     $conpherence_data = $dropdown_data[$conpherence_app];
     if ($conpherence_data['isInstalled']) {
       $message_id = celerity_generate_unique_node_id();
       $message_count_id = celerity_generate_unique_node_id();
       $message_dropdown_id = celerity_generate_unique_node_id();
 
       $message_count_number = $conpherence_data['rawCount'];
 
       if ($message_count_number) {
         $aural[] = phutil_tag(
           'a',
           array(
             'href' => '/conpherence/',
           ),
           pht(
             '%s unread messages.',
             new PhutilNumber($message_count_number)));
       } else {
         $aural[] = pht('No messages.');
       }
 
       $message_count_tag = phutil_tag(
         'span',
         array(
           'id'    => $message_count_id,
           'class' => 'phabricator-main-menu-message-count',
         ),
         $conpherence_data['count']);
 
       $message_icon_tag = javelin_tag(
         'span',
         array(
           'class' => 'phabricator-main-menu-message-icon phui-icon-view '.
                      'phui-font-fa fa-comments',
           'sigil' => 'menu-icon',
         ),
         '');
 
       if ($message_count_number) {
         $container_classes[] = 'message-unread';
       }
 
       $message_tag = phutil_tag(
         'a',
         array(
           'href'  => '/conpherence/',
           'class' => implode(' ', $container_classes),
           'id'    => $message_id,
         ),
         array(
           $message_icon_tag,
           $message_count_tag,
         ));
 
       Javelin::initBehavior(
         'aphlict-dropdown',
         array(
           'bubbleID'    => $message_id,
           'countID'     => $message_count_id,
           'dropdownID'  => $message_dropdown_id,
           'loadingText' => pht('Loading...'),
           'uri'         => '/conpherence/panel/',
           'countType'   => $conpherence_data['countType'],
           'countNumber' => $message_count_number,
           'unreadClass' => 'message-unread',
         ) + self::getFavicons());
 
       $message_notification_dropdown = javelin_tag(
         'div',
         array(
           'id'    => $message_dropdown_id,
           'class' => 'phabricator-notification-menu',
           'sigil' => 'phabricator-notification-menu',
           'style' => 'display: none;',
         ),
         '');
     }
 
     $bubble_tag = '';
     $notification_dropdown = '';
     $notification_app = 'PhabricatorNotificationsApplication';
     $notification_data = $dropdown_data[$notification_app];
     if ($notification_data['isInstalled']) {
       $count_id = celerity_generate_unique_node_id();
       $dropdown_id = celerity_generate_unique_node_id();
       $bubble_id = celerity_generate_unique_node_id();
 
       $count_number = $notification_data['rawCount'];
 
       if ($count_number) {
         $aural[] = phutil_tag(
           'a',
           array(
             'href' => '/notification/',
           ),
           pht(
             '%s unread notifications.',
             new PhutilNumber($count_number)));
       } else {
         $aural[] = pht('No notifications.');
       }
 
       $count_tag = phutil_tag(
         'span',
         array(
           'id'    => $count_id,
           'class' => 'phabricator-main-menu-alert-count',
         ),
         $notification_data['count']);
 
       $icon_tag = javelin_tag(
         'span',
         array(
           'class' => 'phabricator-main-menu-alert-icon phui-icon-view '.
                      'phui-font-fa fa-bell',
           'sigil' => 'menu-icon',
         ),
         '');
 
       if ($count_number) {
         $container_classes[] = 'alert-unread';
       }
 
       $bubble_tag = phutil_tag(
         'a',
         array(
           'href'  => '/notification/',
           'class' => implode(' ', $container_classes),
           'id'    => $bubble_id,
         ),
         array($icon_tag, $count_tag));
 
       Javelin::initBehavior(
         'aphlict-dropdown',
         array(
           'bubbleID'    => $bubble_id,
           'countID'     => $count_id,
           'dropdownID'  => $dropdown_id,
           'loadingText' => pht('Loading...'),
           'uri'         => '/notification/panel/',
           'countType'   => $notification_data['countType'],
           'countNumber' => $count_number,
           'unreadClass' => 'alert-unread',
         ) + self::getFavicons());
 
       $notification_dropdown = javelin_tag(
         'div',
         array(
           'id'    => $dropdown_id,
           'class' => 'phabricator-notification-menu',
           'sigil' => 'phabricator-notification-menu',
           'style' => 'display: none;',
         ),
         '');
     }
 
     // Admin Level Urgent Notification Channel
     $setup_tag = '';
     $setup_notification_dropdown = '';
     if ($viewer && $viewer->getIsAdmin()) {
       $open = PhabricatorSetupCheck::getOpenSetupIssueKeys();
       if ($open) {
         $setup_id = celerity_generate_unique_node_id();
         $setup_count_id = celerity_generate_unique_node_id();
         $setup_dropdown_id = celerity_generate_unique_node_id();
 
         $setup_count_number = count($open);
 
         if ($setup_count_number) {
           $aural[] = phutil_tag(
             'a',
             array(
               'href' => '/config/issue/',
             ),
             pht(
               '%s unresolved issues.',
               new PhutilNumber($setup_count_number)));
         } else {
           $aural[] = pht('No issues.');
         }
 
         $setup_count_tag = phutil_tag(
           'span',
           array(
             'id'    => $setup_count_id,
             'class' => 'phabricator-main-menu-setup-count',
           ),
           $setup_count_number);
 
         $setup_icon_tag = javelin_tag(
           'span',
           array(
             'class' => 'phabricator-main-menu-setup-icon phui-icon-view '.
                        'phui-font-fa fa-exclamation-circle',
             'sigil' => 'menu-icon',
           ),
           '');
 
         if ($setup_count_number) {
           $container_classes[] = 'setup-unread';
         }
 
         $setup_tag = phutil_tag(
           'a',
           array(
             'href'  => '/config/issue/',
             'class' => implode(' ', $container_classes),
             'id'    => $setup_id,
           ),
           array(
             $setup_icon_tag,
             $setup_count_tag,
           ));
 
         Javelin::initBehavior(
           'aphlict-dropdown',
           array(
             'bubbleID'    => $setup_id,
             'countID'     => $setup_count_id,
             'dropdownID'  => $setup_dropdown_id,
             'loadingText' => pht('Loading...'),
             'uri'         => '/config/issue/panel/',
             'countType'   => null,
             'countNumber' => null,
             'unreadClass' => 'setup-unread',
           ) + self::getFavicons());
 
         $setup_notification_dropdown = javelin_tag(
           'div',
           array(
             'id'    => $setup_dropdown_id,
             'class' => 'phabricator-notification-menu',
             'sigil' => 'phabricator-notification-menu',
             'style' => 'display: none;',
           ),
           '');
       }
     }
 
     $user_dropdown = null;
     $user_tag = null;
     if ($viewer->isLoggedIn()) {
       if (!$viewer->getIsEmailVerified()) {
         $bubble_id = celerity_generate_unique_node_id();
         $count_id = celerity_generate_unique_node_id();
         $dropdown_id = celerity_generate_unique_node_id();
 
         $settings_uri = id(new PhabricatorEmailAddressesSettingsPanel())
           ->setViewer($viewer)
           ->setUser($viewer)
           ->getPanelURI();
 
         $user_icon = javelin_tag(
           'span',
           array(
             'class' => 'phabricator-main-menu-setup-icon phui-icon-view '.
                        'phui-font-fa fa-user',
             'sigil' => 'menu-icon',
           ));
 
         $user_count = javelin_tag(
           'span',
           array(
             'class' => 'phabricator-main-menu-setup-count',
             'id' => $count_id,
           ),
           1);
 
         $user_tag = phutil_tag(
           'a',
           array(
             'href' => $settings_uri,
             'class' => 'setup-unread',
             'id' => $bubble_id,
           ),
           array(
             $user_icon,
             $user_count,
           ));
 
         Javelin::initBehavior(
           'aphlict-dropdown',
           array(
             'bubbleID' => $bubble_id,
             'countID' => $count_id,
             'dropdownID' => $dropdown_id,
             'loadingText' => pht('Loading...'),
             'uri' => '/settings/issue/',
             'unreadClass' => 'setup-unread',
           ));
 
         $user_dropdown = javelin_tag(
           'div',
           array(
             'id'    => $dropdown_id,
             'class' => 'phabricator-notification-menu',
             'sigil' => 'phabricator-notification-menu',
             'style' => 'display: none;',
           ));
       }
     }
 
     $dropdowns = array(
       $notification_dropdown,
       $message_notification_dropdown,
       $setup_notification_dropdown,
       $user_dropdown,
     );
 
     return array(
       array(
         $bubble_tag,
         $message_tag,
         $setup_tag,
         $user_tag,
       ),
       $dropdowns,
       $aural,
     );
   }
 
   private function isFullSession(PhabricatorUser $viewer) {
     if (!$viewer->isLoggedIn()) {
       return false;
     }
 
     if (!$viewer->isUserActivated()) {
       return false;
     }
 
     if (!$viewer->hasSession()) {
       return false;
     }
 
     $session = $viewer->getSession();
     if ($session->getIsPartial()) {
       return false;
     }
 
     if (!$session->getSignedLegalpadDocuments()) {
       return false;
     }
 
     $mfa_key = 'security.require-multi-factor-auth';
     $need_mfa = PhabricatorEnv::getEnvConfig($mfa_key);
     if ($need_mfa) {
       $have_mfa = $viewer->getIsEnrolledInMultiFactor();
       if (!$have_mfa) {
         return false;
       }
     }
 
     return true;
   }
 
 }
diff --git a/src/view/phui/PHUIObjectItemListView.php b/src/view/phui/PHUIObjectItemListView.php
index fbc3904586..629feb9139 100644
--- a/src/view/phui/PHUIObjectItemListView.php
+++ b/src/view/phui/PHUIObjectItemListView.php
@@ -1,184 +1,184 @@
 <?php
 
 final class PHUIObjectItemListView extends AphrontTagView {
 
   private $header;
   private $items;
   private $pager;
   private $noDataString;
   private $flush;
   private $simple;
   private $big;
   private $drag;
   private $allowEmptyList;
   private $itemClass = 'phui-oi-standard';
   private $tail = array();
 
   public function setAllowEmptyList($allow_empty_list) {
     $this->allowEmptyList = $allow_empty_list;
     return $this;
   }
 
   public function getAllowEmptyList() {
     return $this->allowEmptyList;
   }
 
   public function setFlush($flush) {
     $this->flush = $flush;
     return $this;
   }
 
   public function setHeader($header) {
     $this->header = $header;
     return $this;
   }
 
   public function setPager($pager) {
     $this->pager = $pager;
     return $this;
   }
 
   public function setSimple($simple) {
     $this->simple = $simple;
     return $this;
   }
 
   public function setBig($big) {
     $this->big = $big;
     return $this;
   }
 
   public function setDrag($drag) {
     $this->drag = $drag;
     $this->setItemClass('phui-oi-drag');
     return $this;
   }
 
   public function setNoDataString($no_data_string) {
     $this->noDataString = $no_data_string;
     return $this;
   }
 
   public function addItem(PHUIObjectItemView $item) {
     $this->items[] = $item;
     return $this;
   }
 
   public function setItemClass($item_class) {
     $this->itemClass = $item_class;
     return $this;
   }
 
   protected function getTagName() {
     return 'ul';
   }
 
   public function newTailButton() {
     $button = id(new PHUIButtonView())
       ->setTag('a')
       ->setColor(PHUIButtonView::GREY)
       ->setIcon('fa-chevron-down')
       ->setText(pht('View All Results'));
 
     $this->tail[] = $button;
 
     return $button;
   }
 
   protected function getTagAttributes() {
     $classes = array();
     $classes[] = 'phui-oi-list-view';
 
     if ($this->flush) {
       $classes[] = 'phui-oi-list-flush';
       require_celerity_resource('phui-oi-flush-ui-css');
     }
 
     if ($this->simple) {
       $classes[] = 'phui-oi-list-simple';
       require_celerity_resource('phui-oi-simple-ui-css');
     }
 
     if ($this->big) {
       $classes[] = 'phui-oi-list-big';
       require_celerity_resource('phui-oi-big-ui-css');
     }
 
     if ($this->drag) {
       $classes[] = 'phui-oi-list-drag';
       require_celerity_resource('phui-oi-drag-ui-css');
     }
 
     return array(
       'class' => $classes,
     );
   }
 
   protected function getTagContent() {
     $viewer = $this->getUser();
     require_celerity_resource('phui-oi-list-view-css');
     require_celerity_resource('phui-oi-color-css');
 
     $header = null;
-    if (strlen($this->header)) {
+    if (phutil_nonempty_string($this->header)) {
       $header = phutil_tag(
         'h1',
         array(
           'class' => 'phui-oi-list-header',
         ),
         $this->header);
     }
 
     if ($this->items) {
       if ($viewer) {
         foreach ($this->items as $item) {
           $item->setUser($viewer);
         }
       }
 
       foreach ($this->items as $item) {
         $item->addClass($this->itemClass);
       }
 
       $items = $this->items;
     } else if ($this->allowEmptyList) {
       $items = null;
     } else {
       $string = nonempty($this->noDataString, pht('No data.'));
       $string = id(new PHUIInfoView())
         ->setSeverity(PHUIInfoView::SEVERITY_NODATA)
         ->appendChild($string);
       $items = phutil_tag(
         'li',
         array(
           'class' => 'phui-oi-empty',
         ),
         $string);
 
     }
 
     $pager = null;
     if ($this->pager) {
       $pager = $this->pager;
     }
 
     $tail = array();
     foreach ($this->tail as $tail_item) {
       $tail[] = phutil_tag(
         'li',
         array(
           'class' => 'phui-oi-tail',
         ),
         $tail_item);
     }
 
     return array(
       $header,
       $items,
       $tail,
       $pager,
       $this->renderChildren(),
     );
   }
 
 }
diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php
index 4bb9c3ea6a..6563101f98 100644
--- a/src/view/phui/PHUIObjectItemView.php
+++ b/src/view/phui/PHUIObjectItemView.php
@@ -1,901 +1,902 @@
 <?php
 
 final class PHUIObjectItemView extends AphrontTagView {
 
   private $objectName;
   private $header;
   private $subhead;
   private $href;
   private $attributes = array();
   private $icons = array();
   private $barColor;
   private $object;
   private $effect;
   private $statusIcon;
   private $handleIcons = array();
   private $bylines = array();
   private $grippable;
   private $actions = array();
   private $headIcons = array();
   private $disabled;
   private $imageURI;
   private $imageHref;
   private $imageIcon;
   private $titleText;
   private $badge;
   private $countdownNum;
   private $countdownNoun;
   private $sideColumn;
   private $coverImage;
   private $description;
   private $clickable;
   private $mapViews = array();
   private $menu;
 
   private $selectableName;
   private $selectableValue;
   private $isSelected;
   private $isForbidden;
 
   public function setDisabled($disabled) {
     $this->disabled = $disabled;
     return $this;
   }
 
   public function getDisabled() {
     return $this->disabled;
   }
 
   public function addHeadIcon($icon) {
     $this->headIcons[] = $icon;
     return $this;
   }
 
   public function setObjectName($name) {
     $this->objectName = $name;
     return $this;
   }
 
   public function setGrippable($grippable) {
     $this->grippable = $grippable;
     return $this;
   }
 
   public function getGrippable() {
     return $this->grippable;
   }
 
   public function setEffect($effect) {
     $this->effect = $effect;
     return $this;
   }
 
   public function getEffect() {
     return $this->effect;
   }
 
   public function setObject($object) {
     $this->object = $object;
     return $this;
   }
 
   public function getObject() {
     return $this->object;
   }
 
   public function setHref($href) {
     $this->href = $href;
     return $this;
   }
 
   public function getHref() {
     return $this->href;
   }
 
   public function setHeader($header) {
     $this->header = $header;
     return $this;
   }
 
   public function setSubHead($subhead) {
     $this->subhead = $subhead;
     return $this;
   }
 
   public function setBadge(PHUIBadgeMiniView $badge) {
     $this->badge = $badge;
     return $this;
   }
 
   public function setCountdown($num, $noun) {
     $this->countdownNum = $num;
     $this->countdownNoun = $noun;
     return $this;
   }
 
   public function setTitleText($title_text) {
     $this->titleText = $title_text;
     return $this;
   }
 
   public function getTitleText() {
     return $this->titleText;
   }
 
   public function getHeader() {
     return $this->header;
   }
 
   public function addByline($byline) {
     $this->bylines[] = $byline;
     return $this;
   }
 
   public function setImageURI($image_uri) {
     $this->imageURI = $image_uri;
     return $this;
   }
 
   public function setImageHref($image_href) {
     $this->imageHref = $image_href;
     return $this;
   }
 
   public function getImageURI() {
     return $this->imageURI;
   }
 
   public function setImageIcon($image_icon) {
     if (!$image_icon instanceof PHUIIconView) {
       $image_icon = id(new PHUIIconView())
         ->setIcon($image_icon);
     }
     $this->imageIcon = $image_icon;
     return $this;
   }
 
   public function getImageIcon() {
     return $this->imageIcon;
   }
 
   public function setCoverImage($image) {
     $this->coverImage = $image;
     return $this;
   }
 
   public function setDescription($description) {
     $this->description = $description;
     return $this;
   }
 
   public function setSelectable(
     $name,
     $value,
     $is_selected,
     $is_forbidden = false) {
 
     $this->selectableName = $name;
     $this->selectableValue = $value;
     $this->isSelected = $is_selected;
     $this->isForbidden = $is_forbidden;
 
     return $this;
   }
 
   public function setClickable($clickable) {
     $this->clickable = $clickable;
     return $this;
   }
 
   public function getClickable() {
     return $this->clickable;
   }
 
   public function setEpoch($epoch) {
     $date = phabricator_dual_datetime($epoch, $this->getUser());
     $this->addIcon('none', $date);
     return $this;
   }
 
   public function addAction(PHUIListItemView $action) {
     if (count($this->actions) >= 3) {
       throw new Exception(pht('Limit 3 actions per item.'));
     }
     $this->actions[] = $action;
     return $this;
   }
 
   public function addIcon($icon, $label = null, $attributes = array()) {
     $this->icons[] = array(
       'icon'  => $icon,
       'label' => $label,
       'attributes' => $attributes,
     );
     return $this;
   }
 
   public function newMenuItem() {
     if (!$this->menu) {
       $this->menu = new FuelMenuView();
     }
 
     return $this->menu->newItem();
   }
 
   public function newMapView() {
     $list = id(new FuelMapView())
       ->addClass('fuel-map-property-list');
     $this->mapViews[] = $list;
     return $list;
   }
 
   /**
    * This method has been deprecated, use @{method:setImageIcon} instead.
    *
    * @deprecated
    */
   public function setIcon($icon) {
     phlog(
       pht('Deprecated call to setIcon(), use setImageIcon() instead.'));
 
     return $this->setImageIcon($icon);
   }
 
   public function setStatusIcon($icon, $label = null) {
     $this->statusIcon = array(
       'icon' => $icon,
       'label' => $label,
     );
     return $this;
   }
 
   public function addHandleIcon(
     PhabricatorObjectHandle $handle,
     $label = null) {
     $this->handleIcons[] = array(
       'icon' => $handle,
       'label' => $label,
     );
     return $this;
   }
 
   public function setBarColor($bar_color) {
     $this->barColor = $bar_color;
     return $this;
   }
 
   public function getBarColor() {
     return $this->barColor;
   }
 
   public function addAttribute($attribute) {
     if (!empty($attribute)) {
       $this->attributes[] = $attribute;
     }
     return $this;
   }
 
   public function setSideColumn($column) {
     $this->sideColumn = $column;
     return $this;
   }
 
   protected function getTagName() {
     return 'li';
   }
 
   protected function getTagAttributes() {
     $sigils = array();
 
     $item_classes = array();
     $item_classes[] = 'phui-oi';
 
     if ($this->icons) {
       $item_classes[] = 'phui-oi-with-icons';
     }
 
     if ($this->attributes) {
       $item_classes[] = 'phui-oi-with-attrs';
     }
 
     if ($this->handleIcons) {
       $item_classes[] = 'phui-oi-with-handle-icons';
     }
 
     if ($this->barColor) {
       $item_classes[] = 'phui-oi-bar-color-'.$this->barColor;
     } else {
       $item_classes[] = 'phui-oi-no-bar';
     }
 
     if ($this->actions) {
       $n = count($this->actions);
       $item_classes[] = 'phui-oi-with-actions';
       $item_classes[] = 'phui-oi-with-'.$n.'-actions';
     }
 
     if ($this->disabled) {
       $item_classes[] = 'phui-oi-disabled';
     } else {
       $item_classes[] = 'phui-oi-enabled';
     }
 
     switch ($this->effect) {
       case 'highlighted':
         $item_classes[] = 'phui-oi-highlighted';
         break;
       case 'selected':
         $item_classes[] = 'phui-oi-selected';
         break;
       case 'visited':
         $item_classes[] = 'phui-oi-visited';
         break;
       case null:
         break;
       default:
         throw new Exception(pht('Invalid effect!'));
     }
 
     if ($this->isForbidden) {
       $item_classes[] = 'phui-oi-forbidden';
     } else if ($this->isSelected) {
       $item_classes[] = 'phui-oi-selected';
     }
 
     if ($this->selectableName !== null && !$this->isForbidden) {
       $item_classes[] = 'phui-oi-selectable';
       $sigils[] = 'phui-oi-selectable';
 
       Javelin::initBehavior('phui-selectable-list');
     }
 
     $is_grippable = $this->getGrippable();
     if ($is_grippable !== null) {
       $item_classes[] = 'phui-oi-has-grip';
       if ($is_grippable) {
         $item_classes[] = 'phui-oi-grippable';
       } else {
         $item_classes[] = 'phui-oi-ungrippable';
       }
     }
 
     if ($this->getImageURI()) {
       $item_classes[] = 'phui-oi-with-image';
     }
 
     if ($this->getImageIcon()) {
       $item_classes[] = 'phui-oi-with-image-icon';
     }
 
     if ($this->getClickable()) {
       Javelin::initBehavior('linked-container');
 
       $item_classes[] = 'phui-oi-linked-container';
       $sigils[] = 'linked-container';
     }
 
     return array(
       'class' => $item_classes,
       'sigil' => $sigils,
     );
   }
 
   protected function getTagContent() {
     $viewer = $this->getUser();
 
     $content_classes = array();
     $content_classes[] = 'phui-oi-content';
 
     $header_name = array();
 
     if ($viewer) {
       $header_name[] = id(new PHUISpacesNamespaceContextView())
         ->setUser($viewer)
         ->setObject($this->object);
     }
 
     if ($this->objectName) {
       $header_name[] = array(
         javelin_tag(
           'span',
           array(
             'class' => 'phui-oi-objname',
             'sigil' => 'ungrabbable',
           ),
           $this->objectName),
         ' ',
       );
     }
 
     $title_text = null;
     if ($this->titleText) {
       $title_text = $this->titleText;
     } else if ($this->href) {
       $title_text = $this->header;
     }
 
     $header_link = phutil_tag(
       $this->href ? 'a' : 'div',
       array(
         'href' => $this->href,
         'class' => 'phui-oi-link',
         'title' => $title_text,
       ),
       $this->header);
 
     $description_tag = null;
     if ($this->description) {
       $decription_id = celerity_generate_unique_node_id();
       $description_tag = id(new PHUITagView())
         ->setIcon('fa-ellipsis-h')
         ->addClass('phui-oi-description-tag')
         ->setType(PHUITagView::TYPE_SHADE)
         ->setColor(PHUITagView::COLOR_GREY)
         ->addSigil('jx-toggle-class')
         ->setSlimShady(true)
         ->setMetaData(array(
           'map' => array(
             $decription_id => 'phui-oi-description-reveal',
           ),
         ));
     }
 
     $header = phutil_tag(
       'div',
       array(
         'class' => 'phui-oi-name',
       ),
       array(
         $this->headIcons,
         $header_name,
         $header_link,
         $description_tag,
       ));
 
     $icons = array();
     if ($this->icons) {
       $icon_list = array();
       foreach ($this->icons as $spec) {
         $icon = $spec['icon'];
         $icon = id(new PHUIIconView())
           ->setIcon($icon)
           ->addClass('phui-oi-icon-image');
 
         if (isset($spec['attributes']['tip'])) {
           $sigil = 'has-tooltip';
           $meta = array(
             'tip' => $spec['attributes']['tip'],
             'align' => 'W',
           );
           $icon->addSigil($sigil);
           $icon->setMetadata($meta);
         }
 
         $label = phutil_tag(
           'span',
           array(
             'class' => 'phui-oi-icon-label',
           ),
           $spec['label']);
 
         $classes = array();
         $classes[] = 'phui-oi-icon';
         if (isset($spec['attributes']['class'])) {
           $classes[] = $spec['attributes']['class'];
         }
 
         $icon_list[] = javelin_tag(
           'li',
           array(
             'class' => implode(' ', $classes),
           ),
           array(
             $icon,
             $label,
           ));
       }
 
       $icons[] = phutil_tag(
         'ul',
         array(
           'class' => 'phui-oi-icons',
         ),
         $icon_list);
     }
 
     $handle_bar = null;
     if ($this->handleIcons) {
       $handle_bar = array();
       foreach ($this->handleIcons as $handleicon) {
         $handle_bar[] =
           $this->renderHandleIcon($handleicon['icon'], $handleicon['label']);
       }
       $handle_bar = phutil_tag(
         'li',
         array(
           'class' => 'phui-oi-handle-icons',
         ),
         $handle_bar);
     }
 
     $bylines = array();
     if ($this->bylines) {
       foreach ($this->bylines as $byline) {
         $bylines[] = phutil_tag(
           'div',
           array(
             'class' => 'phui-oi-byline',
           ),
           $byline);
       }
       $bylines = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-bylines',
         ),
         $bylines);
     }
 
     $subhead = null;
     if ($this->subhead) {
       $subhead = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-subhead',
         ),
         $this->subhead);
     }
 
     if ($this->description) {
       $subhead = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-subhead phui-oi-description',
           'id' => $decription_id,
         ),
         $this->description);
     }
 
     if ($icons) {
       $icons = phutil_tag(
         'div',
         array(
           'class' => 'phui-object-icon-pane',
         ),
         $icons);
     }
 
     $attrs = null;
     if ($this->attributes || $handle_bar) {
       $attrs = array();
       $spacer = phutil_tag(
         'span',
         array(
           'class' => 'phui-oi-attribute-spacer',
         ),
         "\xC2\xB7");
       $first = true;
       foreach ($this->attributes as $attribute) {
         $attrs[] = phutil_tag(
           'li',
           array(
             'class' => 'phui-oi-attribute',
           ),
           array(
             ($first ? null : $spacer),
             $attribute,
           ));
         $first = false;
       }
 
       $attrs = phutil_tag(
         'ul',
         array(
           'class' => 'phui-oi-attributes',
         ),
         array(
           $handle_bar,
           $attrs,
         ));
     }
 
     $status = null;
     if ($this->statusIcon) {
       $icon = $this->statusIcon;
       $status = $this->renderStatusIcon($icon['icon'], $icon['label']);
     }
 
     $grippable = null;
     if ($this->getGrippable() !== null) {
       $grippable = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-grip',
         ),
         '');
     }
 
     $map_views = null;
     if ($this->mapViews) {
       $grid = id(new FuelGridView())
         ->addClass('fuel-grid-property-list');
 
       $row = $grid->newRow();
       foreach ($this->mapViews as $map_view) {
         $row->newCell()
           ->setContent($map_view);
       }
 
       $map_views = $grid;
     }
 
     $content = phutil_tag(
       'div',
       array(
         'class' => implode(' ', $content_classes),
       ),
       array(
         $subhead,
         $attrs,
         $map_views,
         $this->renderChildren(),
       ));
 
     $image = null;
     if ($this->getImageURI()) {
       $image = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-image',
           'style' => 'background-image: url('.$this->getImageURI().')',
         ),
         '');
     } else if ($this->getImageIcon()) {
       $image = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-image-icon',
         ),
         $this->getImageIcon());
     }
 
-    if ($image && (strlen($this->href) || strlen($this->imageHref))) {
+    if ($image && (phutil_nonempty_string($this->href) ||
+        phutil_nonempty_string($this->imageHref))) {
       $image_href = ($this->imageHref) ? $this->imageHref : $this->href;
       $image = phutil_tag(
         'a',
         array(
           'href' => $image_href,
         ),
         $image);
     }
 
     /* Build a fake table */
     $column0 = null;
     if ($status) {
       $column0 = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-col0',
         ),
         $status);
     }
 
     if ($this->badge) {
       $column0 = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-col0 phui-oi-badge',
         ),
         $this->badge);
     }
 
     if ($this->countdownNum) {
       $countdown = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-countdown-number',
         ),
         array(
           phutil_tag_div('', $this->countdownNum),
           phutil_tag_div('', $this->countdownNoun),
         ));
       $column0 = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-col0 phui-oi-countdown',
         ),
         $countdown);
     }
 
     if ($this->selectableName !== null) {
       if (!$this->isForbidden) {
         $checkbox = phutil_tag(
           'input',
           array(
             'type' => 'checkbox',
             'name' => $this->selectableName,
             'value' => $this->selectableValue,
             'checked' => ($this->isSelected ? 'checked' : null),
           ));
       } else {
         $checkbox = null;
       }
 
       $column0 = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-col0 phui-oi-checkbox',
         ),
         $checkbox);
     }
 
     $column1 = phutil_tag(
       'div',
       array(
         'class' => 'phui-oi-col1',
       ),
       array(
         $header,
         $content,
       ));
 
     $column2 = null;
     if ($icons || $bylines) {
       $column2 = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-col2',
         ),
         array(
           $icons,
           $bylines,
         ));
     }
 
     /* Fixed width, right column container. */
     $column3 = null;
     if ($this->sideColumn) {
       $column3 = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-col2 phui-oi-side-column',
         ),
         array(
           $this->sideColumn,
         ));
     }
 
     $table = phutil_tag(
       'div',
       array(
         'class' => 'phui-oi-table',
       ),
       phutil_tag_div(
         'phui-oi-table-row',
         array(
           $column0,
           $column1,
           $column2,
           $column3,
         )));
 
     $box = phutil_tag(
       'div',
       array(
         'class' => 'phui-oi-content-box',
       ),
       array(
         $grippable,
         $table,
       ));
 
     $actions = array();
     if ($this->actions) {
       Javelin::initBehavior('phabricator-tooltips');
 
       foreach (array_reverse($this->actions) as $action) {
         $action->setRenderNameAsTooltip(true);
         $actions[] = $action;
       }
       $actions = phutil_tag(
         'ul',
         array(
           'class' => 'phui-oi-actions',
         ),
         $actions);
     }
 
     $frame_content = phutil_tag(
       'div',
       array(
         'class' => 'phui-oi-frame-content',
       ),
       array(
         $actions,
         $image,
         $box,
       ));
 
     if ($this->menu) {
       $grid_view = id(new FuelGridView())
         ->addClass('fuel-grid-tablet');
       $grid_row = $grid_view->newRow();
 
       $grid_row->newCell()
         ->setContent($frame_content);
 
       $menu = $this->menu;
 
       $grid_row->newCell()
         ->addClass('phui-oi-menu')
         ->setContent($menu);
 
       $frame_content = $grid_view;
     }
 
     $frame_cover = null;
     if ($this->coverImage) {
       $cover_image = phutil_tag(
         'img',
         array(
           'src' => $this->coverImage,
           'class' => 'phui-oi-cover-image',
         ));
 
       $frame_cover = phutil_tag(
         'div',
         array(
           'class' => 'phui-oi-frame-cover',
         ),
         $cover_image);
     }
 
     $frame = phutil_tag(
       'div',
       array(
         'class' => 'phui-oi-frame',
       ),
       array(
         $frame_cover,
         $frame_content,
       ));
 
     return $frame;
   }
 
   private function renderStatusIcon($icon, $label) {
     Javelin::initBehavior('phabricator-tooltips');
 
     $icon = id(new PHUIIconView())
       ->setIcon($icon);
 
     $options = array(
       'class' => 'phui-oi-status-icon',
     );
 
     if (strlen($label)) {
       $options['sigil'] = 'has-tooltip';
       $options['meta']  = array('tip' => $label, 'size' => 300);
     }
 
     return javelin_tag('div', $options, $icon);
   }
 
 
   private function renderHandleIcon(PhabricatorObjectHandle $handle, $label) {
     Javelin::initBehavior('phabricator-tooltips');
 
     $options = array(
       'class' => 'phui-oi-handle-icon',
       'style' => 'background-image: url('.$handle->getImageURI().')',
     );
 
     if (strlen($label)) {
       $options['sigil'] = 'has-tooltip';
       $options['meta']  = array('tip' => $label, 'align' => 'E');
     }
 
     return javelin_tag('span', $options, '');
   }
 
 }