diff --git a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
index a9a836c7c0..b1ea4edff9 100644
--- a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
+++ b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
@@ -1,462 +1,462 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 final class PhabricatorPeopleEditController
   extends PhabricatorPeopleController {
 
   public function shouldRequireAdmin() {
     return true;
   }
 
   private $id;
   private $view;
 
   public function willProcessRequest(array $data) {
     $this->id = idx($data, 'id');
     $this->view = idx($data, 'view');
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
     $admin = $request->getUser();
 
     if ($this->id) {
       $user = id(new PhabricatorUser())->load($this->id);
       if (!$user) {
         return new Aphront404Response();
       }
     } else {
       $user = new PhabricatorUser();
     }
 
     $views = array(
       'basic'     => 'Basic Information',
       'role'      => 'Edit Role',
       'cert'      => 'Conduit Certificate',
     );
 
     if (!$user->getID()) {
       $view = 'basic';
     } else if (isset($views[$this->view])) {
       $view = $this->view;
     } else {
       $view = 'basic';
     }
 
     $content = array();
 
     if ($request->getStr('saved')) {
       $notice = new AphrontErrorView();
       $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
       $notice->setTitle('Changes Saved');
       $notice->appendChild('<p>Your changes were saved.</p>');
       $content[] = $notice;
     }
 
     switch ($view) {
       case 'basic':
         $response = $this->processBasicRequest($user);
         break;
       case 'role':
         $response = $this->processRoleRequest($user);
         break;
       case 'cert':
         $response = $this->processCertificateRequest($user);
         break;
     }
 
     if ($response instanceof AphrontResponse) {
       return $response;
     }
 
     $content[] = $response;
 
     if ($user->getID()) {
       $side_nav = new AphrontSideNavView();
       $side_nav->appendChild($content);
       foreach ($views as $key => $name) {
         $side_nav->addNavItem(
           phutil_render_tag(
             'a',
             array(
               'href' => '/people/edit/'.$user->getID().'/'.$key.'/',
               'class' => ($key == $view)
                 ? 'aphront-side-nav-selected'
                 : null,
             ),
             phutil_escape_html($name)));
       }
       $content = $side_nav;
     }
 
     return $this->buildStandardPageResponse(
       $content,
       array(
         'title' => 'Edit User',
       ));
   }
 
   private function processBasicRequest(PhabricatorUser $user) {
     $request = $this->getRequest();
     $admin = $request->getUser();
 
     $e_username = true;
     $e_realname = true;
     $e_email    = true;
     $errors = array();
 
     $welcome_checked = true;
 
     $request = $this->getRequest();
     if ($request->isFormPost()) {
       $welcome_checked = $request->getInt('welcome');
 
       if (!$user->getID()) {
         $user->setUsername($request->getStr('username'));
         $user->setEmail($request->getStr('email'));
 
         if ($request->getStr('role') == 'agent') {
           $user->setIsSystemAgent(true);
         }
       }
       $user->setRealName($request->getStr('realname'));
 
       if (!strlen($user->getUsername())) {
         $errors[] = "Username is required.";
         $e_username = 'Required';
       } else if (!PhabricatorUser::validateUsername($user->getUsername())) {
         $errors[] = "Username must consist of only numbers and letters.";
         $e_username = 'Invalid';
       } else {
         $e_username = null;
       }
 
       if (!strlen($user->getRealName())) {
         $errors[] = 'Real name is required.';
         $e_realname = 'Required';
       } else {
         $e_realname = null;
       }
 
       if (!strlen($user->getEmail())) {
         $errors[] = 'Email is required.';
         $e_email = 'Required';
       } else {
         $e_email = null;
       }
 
       if (!$errors) {
         try {
           $is_new = !$user->getID();
 
           $user->save();
 
           if ($is_new) {
             $log = PhabricatorUserLog::newLog(
               $admin,
               $user,
               PhabricatorUserLog::ACTION_CREATE);
             $log->save();
 
             if ($welcome_checked) {
               $user->sendWelcomeEmail($admin);
             }
           }
 
           $response = id(new AphrontRedirectResponse())
             ->setURI('/people/edit/'.$user->getID().'/?saved=true');
           return $response;
         } catch (AphrontQueryDuplicateKeyException $ex) {
           $errors[] = 'Username and email must be unique.';
 
           $same_username = id(new PhabricatorUser())
             ->loadOneWhere('username = %s', $user->getUsername());
           $same_email = id(new PhabricatorUser())
             ->loadOneWhere('email = %s', $user->getEmail());
 
           if ($same_username) {
             $e_username = 'Duplicate';
           }
 
           if ($same_email) {
             $e_email = 'Duplicate';
           }
         }
       }
     }
 
     $error_view = null;
     if ($errors) {
       $error_view = id(new AphrontErrorView())
         ->setTitle('Form Errors')
         ->setErrors($errors);
     }
 
     $form = new AphrontFormView();
     $form->setUser($admin);
     if ($user->getID()) {
       $form->setAction('/people/edit/'.$user->getID().'/');
     } else {
       $form->setAction('/people/edit/');
     }
 
     if ($user->getID()) {
       $is_immutable = true;
     } else {
       $is_immutable = false;
     }
 
     $form
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel('Username')
           ->setName('username')
           ->setValue($user->getUsername())
           ->setError($e_username)
           ->setDisabled($is_immutable)
           ->setCaption('Usernames are permanent and can not be changed later!'))
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel('Real Name')
           ->setName('realname')
           ->setValue($user->getRealName())
           ->setError($e_realname))
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel('Email')
           ->setName('email')
           ->setDisabled($is_immutable)
           ->setValue($user->getEmail())
           ->setError($e_email))
       ->appendChild($this->getRoleInstructions());
 
     if (!$user->getID()) {
       $form
         ->appendChild(
           id(new AphrontFormSelectControl())
             ->setLabel('Role')
             ->setName('role')
             ->setValue('user')
             ->setOptions(
               array(
                 'user'  => 'Normal User',
                 'agent' => 'System Agent',
               ))
             ->setCaption(
               'You can create a "system agent" account for bots, scripts, '.
               'etc.'))
         ->appendChild(
           id(new AphrontFormCheckboxControl())
             ->addCheckbox(
               'welcome',
               1,
               'Send "Welcome to Phabricator" email.',
               $welcome_checked));
     } else {
       $form->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('Role')
           ->setValue(
             $user->getIsSystemAgent()
               ? 'System Agent'
               : 'Normal User'));
     }
 
     $form
       ->appendChild(
         id(new AphrontFormSubmitControl())
           ->setValue('Save'));
 
     $panel = new AphrontPanelView();
     if ($user->getID()) {
       $panel->setHeader('Edit User');
     } else {
       $panel->setHeader('Create New User');
     }
 
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
 
     return array($error_view, $panel);
   }
 
   private function processRoleRequest(PhabricatorUser $user) {
     $request = $this->getRequest();
     $admin = $request->getUser();
 
     $is_self = ($user->getID() == $admin->getID());
 
     $errors = array();
 
     if ($request->isFormPost()) {
 
       $log_template = PhabricatorUserLog::newLog(
         $admin,
         $user,
         null);
 
       $logs = array();
 
       if ($is_self) {
         $errors[] = "You can not edit your own role.";
       } else {
         $new_admin = (bool)$request->getBool('is_admin');
         $old_admin = (bool)$user->getIsAdmin();
         if ($new_admin != $old_admin) {
           $log = clone $log_template;
           $log->setAction(PhabricatorUserLog::ACTION_ADMIN);
           $log->setOldValue($old_admin);
           $log->setNewValue($new_admin);
           $user->setIsAdmin($new_admin);
           $logs[] = $log;
         }
 
         $new_disabled = (bool)$request->getBool('is_disabled');
         $old_disabled = (bool)$user->getIsDisabled();
         if ($new_disabled != $old_disabled) {
           $log = clone $log_template;
           $log->setAction(PhabricatorUserLog::ACTION_DISABLE);
           $log->setOldValue($old_disabled);
           $log->setNewValue($new_disabled);
           $user->setIsDisabled($new_disabled);
           $logs[] = $log;
         }
       }
 
       if (!$errors) {
         $user->save();
         foreach ($logs as $log) {
           $log->save();
         }
         return id(new AphrontRedirectResponse())
           ->setURI($request->getRequestURI()->alter('saved', 'true'));
       }
     }
 
     $error_view = null;
     if ($errors) {
       $error_view = id(new AphrontErrorView())
         ->setTitle('Form Errors')
         ->setErrors($errors);
     }
 
 
     $form = id(new AphrontFormView())
       ->setUser($admin)
       ->setAction($request->getRequestURI()->alter('saved', null));
 
     if ($is_self) {
       $form->appendChild(
         '<p class="aphront-form-instructions">NOTE: You can not edit your own '.
         'role.</p>');
     }
 
     $form
       ->appendChild($this->getRoleInstructions())
       ->appendChild(
         id(new AphrontFormCheckboxControl())
           ->addCheckbox(
             'is_admin',
             1,
             'Admin: wields absolute power.',
             $user->getIsAdmin())
           ->setDisabled($is_self))
       ->appendChild(
         id(new AphrontFormCheckboxControl())
           ->addCheckbox(
             'is_disabled',
             1,
             'Disabled: can not login.',
             $user->getIsDisabled())
           ->setDisabled($is_self));
 
     if (!$is_self) {
       $form
         ->appendChild(
           id(new AphrontFormSubmitControl())
             ->setValue('Edit Role'));
     }
 
     $panel = new AphrontPanelView();
     $panel->setHeader('Edit Role');
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $panel->appendChild($form);
 
     return array($error_view, $panel);
   }
 
   private function processCertificateRequest($user) {
     $request = $this->getRequest();
     $admin = $request->getUser();
 
 
     $form = new AphrontFormView();
     $form
       ->setUser($admin)
       ->setAction($request->getRequestURI())
       ->appendChild(
         '<p class="aphront-form-instructions">You can use this certificate '.
         'to write scripts or bots which interface with Phabricator over '.
         'Conduit.</p>');
 
     if ($user->getIsSystemAgent()) {
       $form
         ->appendChild(
           id(new AphrontFormTextControl())
             ->setLabel('Username')
             ->setValue($user->getUsername()))
         ->appendChild(
           id(new AphrontFormTextAreaControl())
             ->setLabel('Certificate')
             ->setValue($user->getConduitCertificate()));
     } else {
       $form->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('Certificate')
           ->setValue(
             'You may only view the certificates of System Agents.'));
     }
 
     $panel = new AphrontPanelView();
     $panel->setHeader('Conduit Certificate');
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
 
     $panel->appendChild($form);
 
     return array($panel);
   }
 
   private function getRoleInstructions() {
     $roles_link = phutil_render_tag(
       'a',
       array(
         'href'   => PhabricatorEnv::getDoclink(
-          'article/User_Guide:_Account_Roles.html'),
+          'article/User_Guide_Account_Roles.html'),
         'target' => '_blank',
       ),
       'User Guide: Account Roles');
 
     return
       '<p class="aphront-form-instructions">'.
         'For a detailed explanation of account roles, see '.
         $roles_link.'.'.
       '</p>';
   }
 
 }
diff --git a/src/applications/people/controller/settings/panels/preferences/PhabricatorUserPreferenceSettingsPanelController.php b/src/applications/people/controller/settings/panels/preferences/PhabricatorUserPreferenceSettingsPanelController.php
index 29a47d64ed..8281c1ee6e 100644
--- a/src/applications/people/controller/settings/panels/preferences/PhabricatorUserPreferenceSettingsPanelController.php
+++ b/src/applications/people/controller/settings/panels/preferences/PhabricatorUserPreferenceSettingsPanelController.php
@@ -1,127 +1,127 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 final class PhabricatorUserPreferenceSettingsPanelController
   extends PhabricatorUserSettingsPanelController {
 
   public function processRequest() {
 
     $request = $this->getRequest();
     $user = $request->getUser();
     $preferences = $user->loadPreferences();
 
     $pref_monospaced  = PhabricatorUserPreferences::PREFERENCE_MONOSPACED;
     $pref_editor      = PhabricatorUserPreferences::PREFERENCE_EDITOR;
     $pref_titles      = PhabricatorUserPreferences::PREFERENCE_TITLES;
 
     if ($request->isFormPost()) {
       $monospaced = $request->getStr($pref_monospaced);
 
       // Prevent the user from doing stupid things.
       $monospaced = preg_replace('/[^a-z0-9 ,"]+/i', '', $monospaced);
 
       $preferences->setPreference($pref_titles, $request->getStr($pref_titles));
       $preferences->setPreference($pref_editor, $request->getStr($pref_editor));
       $preferences->setPreference($pref_monospaced, $monospaced);
 
       $preferences->save();
       return id(new AphrontRedirectResponse())
         ->setURI('/settings/page/preferences/?saved=true');
     }
 
     $example_string = <<<EXAMPLE
 // This is what your monospaced font currently looks like.
 function helloWorld() {
   alert("Hello world!");
 }
 EXAMPLE;
 
     $editor_doc_link = phutil_render_tag(
       'a',
       array(
         'href' => PhabricatorEnv::getDoclink(
-          'article/User_Guide:_Configuring_an_External_Editor.html'),
+          'article/User_Guide_Configuring_an_External_Editor.html'),
       ),
       'User Guide: Configuring an External Editor');
 
     $form = id(new AphrontFormView())
       ->setUser($user)
       ->setAction('/settings/page/preferences/')
       ->appendChild(
         id(new AphrontFormSelectControl())
           ->setLabel('Page Titles')
           ->setName($pref_titles)
           ->setValue($preferences->getPreference($pref_titles))
           ->setOptions(
             array(
               'glyph' =>
               "In page titles, show Tool names as unicode glyphs: \xE2\x9A\x99",
               'text' =>
               'In page titles, show Tool names as plain text: [Differential]',
             )))
       ->appendChild(
         id(new AphrontFormTextControl())
         ->setLabel('Editor Link')
         ->setName($pref_editor)
         ->setCaption(
           'Link to edit files in external editor. '.
           '%f is replaced by filename, %l by line number, %r by repository '.
           'callsign. '.
           "For documentation, see {$editor_doc_link}.")
         ->setValue($preferences->getPreference($pref_editor)))
       ->appendChild(
         id(new AphrontFormTextControl())
         ->setLabel('Monospaced Font')
         ->setName($pref_monospaced)
         ->setCaption(
           'Overrides default fonts in tools like Differential. '.
           '(Default: 10px "Menlo", "Consolas", "Monaco", '.
           'monospace)')
         ->setValue($preferences->getPreference($pref_monospaced)))
       ->appendChild(
         id(new AphrontFormMarkupControl())
         ->setValue(
           '<pre class="PhabricatorMonospaced">'.
           phutil_escape_html($example_string).
           '</pre>'))
       ->appendChild(
         id(new AphrontFormSubmitControl())
           ->setValue('Save Preferences'));
 
     $panel = new AphrontPanelView();
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
     $panel->setHeader('Display Preferences');
     $panel->appendChild($form);
 
     $error_view = null;
     if ($request->getStr('saved') === 'true') {
       $error_view = id(new AphrontErrorView())
         ->setTitle('Preferences Saved')
         ->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
         ->setErrors(array('Your preferences have been saved.'));
     }
 
     return id(new AphrontNullView())
       ->appendChild(
         array(
           $error_view,
           $panel,
         ));
   }
 }
 
diff --git a/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php b/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php
index da29909d43..d0c9276ea3 100644
--- a/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php
+++ b/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php
@@ -1,690 +1,690 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 final class PhabricatorRepositoryEditController
   extends PhabricatorRepositoryController {
 
   private $id;
   private $view;
   private $repository;
   private $sideNav;
 
   public function willProcessRequest(array $data) {
     $this->id = $data['id'];
     $this->view = idx($data, 'view');
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
 
     $repository = id(new PhabricatorRepository())->load($this->id);
     if (!$repository) {
       return new Aphront404Response();
     }
 
     $views = array(
       'basic'     => 'Basics',
       'tracking'  => 'Tracking',
     );
 
     $this->repository = $repository;
 
     if (!isset($views[$this->view])) {
       $this->view = head_key($views);
     }
 
     $nav = new AphrontSideNavView();
     foreach ($views as $view => $name) {
       $nav->addNavItem(
         phutil_render_tag(
           'a',
           array(
             'class' => ($view == $this->view
               ? 'aphront-side-nav-selected'
               : null),
             'href'  => '/repository/edit/'.$repository->getID().'/'.$view.'/',
           ),
           phutil_escape_html($name)));
     }
 
     $this->sideNav = $nav;
 
     switch ($this->view) {
       case 'basic':
         return $this->processBasicRequest();
       case 'tracking':
         return $this->processTrackingRequest();
       default:
         throw new Exception("Unknown view.");
     }
   }
 
   protected function processBasicRequest() {
     $request = $this->getRequest();
     $user = $request->getUser();
     $repository = $this->repository;
     $repository_id = $repository->getID();
 
     $errors = array();
 
     $e_name = true;
 
     if ($request->isFormPost()) {
       $repository->setName($request->getStr('name'));
 
       if (!strlen($repository->getName())) {
         $e_name = 'Required';
         $errors[] = 'Repository name is required.';
       } else {
         $e_name = null;
       }
 
       $repository->setDetail('description', $request->getStr('description'));
       $repository->setDetail('encoding', $request->getStr('encoding'));
 
       if (!$errors) {
         $repository->save();
         return id(new AphrontRedirectResponse())
           ->setURI('/repository/edit/'.$repository_id.'/basic/?saved=true');
       }
     }
 
     $error_view = null;
     if ($errors) {
       $error_view = new AphrontErrorView();
       $error_view->setErrors($errors);
       $error_view->setTitle('Form Errors');
     } else if ($request->getStr('saved')) {
       $error_view = new AphrontErrorView();
       $error_view->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
       $error_view->setTitle('Changes Saved');
       $error_view->appendChild(
         'Repository changes were saved.');
     }
 
     $encoding_doc_link = PhabricatorEnv::getDoclink(
-        'article/User_Guide:_UTF-8_and_Character_Encoding.html');
+        'article/User_Guide_UTF-8_and_Character_Encoding.html');
 
     $form = new AphrontFormView();
     $form
       ->setUser($user)
       ->setAction('/repository/edit/'.$repository->getID().'/')
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel('Name')
           ->setName('name')
           ->setValue($repository->getName())
           ->setError($e_name)
           ->setCaption('Human-readable repository name.'))
       ->appendChild(
         id(new AphrontFormTextAreaControl())
           ->setLabel('Description')
           ->setName('description')
           ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)
           ->setValue($repository->getDetail('description')))
       ->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('Callsign')
           ->setName('callsign')
           ->setValue($repository->getCallsign()))
       ->appendChild('
         <p class="aphront-form-instructions">'.
           'If source code in this repository uses a character '.
           'encoding other than UTF-8 (for example, ISO-8859-1), '.
           'specify it here. You can usually leave this field blank. '.
           'See User Guide: '.
           '<a href="'.$encoding_doc_link.'">'.
             'UTF-8 and Character Encoding'.
           '</a> for more information.'.
         '</p>')
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel('Encoding')
           ->setName('encoding')
           ->setValue($repository->getDetail('encoding')))
       ->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('Type')
           ->setName('type')
           ->setValue($repository->getVersionControlSystem()))
       ->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('ID')
           ->setValue($repository->getID()))
       ->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('PHID')
           ->setValue($repository->getPHID()))
       ->appendChild(
         id(new AphrontFormSubmitControl())
           ->setValue('Save'));
 
     $panel = new AphrontPanelView();
     $panel->setHeader('Edit Repository');
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
 
 
     $nav = $this->sideNav;
 
     $nav->appendChild($error_view);
     $nav->appendChild($panel);
 
     return $this->buildStandardPageResponse(
       $nav,
       array(
         'title' => 'Edit Repository',
       ));
   }
 
   private function processTrackingRequest() {
     $request = $this->getRequest();
     $user = $request->getUser();
     $repository = $this->repository;
     $repository_id = $repository->getID();
 
     $errors = array();
 
     $e_uri = null;
     $e_path = null;
 
     $is_git = false;
     $is_svn = false;
     $is_mercurial = false;
 
     $e_ssh_key = null;
     $e_ssh_keyfile = null;
     $e_branch = null;
 
     switch ($repository->getVersionControlSystem()) {
       case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
         $is_git = true;
         break;
       case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
         $is_svn = true;
         break;
       case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
         $is_mercurial = true;
         break;
       default:
         throw new Exception("Unsupported VCS!");
     }
 
     $has_branches       = ($is_git || $is_mercurial);
     $has_local          = ($is_git || $is_mercurial);
     $has_branch_filter  = ($is_git);
     $has_http_support   = $is_svn;
 
     if ($request->isFormPost()) {
       $tracking = ($request->getStr('tracking') == 'enabled' ? true : false);
       $repository->setDetail('tracking-enabled', $tracking);
       $repository->setDetail('remote-uri', $request->getStr('uri'));
       if ($has_local) {
         $repository->setDetail('local-path', $request->getStr('path'));
       }
 
       if ($has_branch_filter) {
         $branch_filter = $request->getStrList('branch-filter');
         $branch_filter = array_fill_keys($branch_filter, true);
 
         $repository->setDetail('branch-filter', $branch_filter);
       }
 
       $repository->setDetail(
         'pull-frequency',
         max(1, $request->getInt('frequency')));
 
       if ($has_branches) {
         $repository->setDetail(
           'default-branch',
           $request->getStr('default-branch'));
         if ($is_git) {
           $branch_name = $repository->getDetail('default-branch');
           if (strpos($branch_name, '/') !== false) {
             $e_branch = 'Invalid';
             $errors[] = "Your branch name should not specify an explicit ".
                         "remote. For instance, use 'master', not ".
                         "'origin/master'.";
           }
         }
       }
 
       $repository->setDetail(
         'default-owners-path',
         $request->getStr(
           'default-owners-path',
           '/'));
 
       $repository->setDetail('ssh-login', $request->getStr('ssh-login'));
       $repository->setDetail('ssh-key', $request->getStr('ssh-key'));
       $repository->setDetail('ssh-keyfile', $request->getStr('ssh-keyfile'));
 
       $repository->setDetail('http-login', $request->getStr('http-login'));
       $repository->setDetail('http-pass',  $request->getStr('http-pass'));
 
       if ($repository->getDetail('ssh-key') &&
           $repository->getDetail('ssh-keyfile')) {
         $errors[] =
           "Specify only one of 'SSH Private Key' and 'SSH Private Key File', ".
           "not both.";
         $e_ssh_key = 'Choose Only One';
         $e_ssh_keyfile = 'Choose Only One';
       }
 
       $repository->setDetail(
         'herald-disabled',
         $request->getInt('herald-disabled', 0));
 
       if ($is_svn) {
         $repository->setUUID($request->getStr('uuid'));
         $subpath = ltrim($request->getStr('svn-subpath'), '/');
         if ($subpath) {
           $subpath = rtrim($subpath, '/').'/';
         }
         $repository->setDetail('svn-subpath', $subpath);
       }
 
       $repository->setDetail(
         'detail-parser',
         $request->getStr(
           'detail-parser',
           'PhabricatorRepositoryDefaultCommitMessageDetailParser'));
 
       if ($tracking) {
         if (!$repository->getDetail('remote-uri')) {
           $e_uri = 'Required';
           $errors[] = "Repository URI is required.";
         } else if ($is_svn &&
           !preg_match('@/$@', $repository->getDetail('remote-uri'))) {
 
           $e_uri = 'Invalid';
           $errors[] = 'Subversion Repository Root must end in a slash ("/").';
         } else {
           $e_uri = null;
         }
 
         if ($has_local) {
           if (!$repository->getDetail('local-path')) {
             $e_path = 'Required';
             $errors[] = "Local path is required.";
           } else {
             $e_path = null;
           }
         }
       }
 
       if (!$errors) {
         $repository->save();
         return id(new AphrontRedirectResponse())
           ->setURI('/repository/edit/'.$repository_id.'/tracking/?saved=true');
       }
     }
 
     $error_view = null;
     if ($errors) {
       $error_view = new AphrontErrorView();
       $error_view->setErrors($errors);
       $error_view->setTitle('Form Errors');
     } else if ($request->getStr('saved')) {
       $error_view = new AphrontErrorView();
       $error_view->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
       $error_view->setTitle('Changes Saved');
       $error_view->appendChild(
         'Tracking changes were saved. You may need to restart the daemon '.
         'before changes will take effect.');
     } else if (!$repository->isTracked()) {
       $error_view = new AphrontErrorView();
       $error_view->setSeverity(AphrontErrorView::SEVERITY_WARNING);
       $error_view->setTitle('Repository Not Tracked');
       $error_view->appendChild(
         'Tracking is currently "Disabled" for this repository, so it will '.
         'not be imported into Phabricator. You can enable it below.');
     }
 
     switch ($repository->getVersionControlSystem()) {
       case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
         $is_git = true;
         break;
       case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
         $is_svn = true;
         break;
     }
 
     $doc_href = PhabricatorEnv::getDoclink('article/Diffusion_User_Guide.html');
     $user_guide_link = phutil_render_tag(
       'a',
       array(
         'href' => $doc_href,
       ),
       'Diffusion User Guide');
 
     $form = new AphrontFormView();
     $form
       ->setUser($user)
       ->setAction('/repository/edit/'.$repository->getID().'/tracking/')
       ->appendChild(
         '<p class="aphront-form-instructions">Phabricator can track '.
         'repositories, importing commits as they happen and notifying '.
         'Differential, Diffusion, Herald, and other services. To enable '.
         'tracking for a repository, configure it here and then start (or '.
         'restart) the daemons. More information is available in the '.
         '<strong>'.$user_guide_link.'</strong>.</p>');
 
     $form
       ->appendChild(
         id(new AphrontFormInsetView())
           ->setTitle('Basics')
           ->appendChild(id(new AphrontFormStaticControl())
             ->setLabel('Repository Name')
             ->setValue($repository->getName()))
           ->appendChild(id(new AphrontFormSelectControl())
             ->setName('tracking')
             ->setLabel('Tracking')
             ->setOptions(array(
                 'disabled'  => 'Disabled',
                 'enabled'   => 'Enabled',
                 ))
             ->setValue(
               $repository->isTracked()
               ? 'enabled'
               : 'disabled')));
 
     $inset = new AphrontFormInsetView();
     $inset->setTitle('Remote URI');
 
     $clone_command = null;
     $fetch_command = null;
     if ($is_git) {
       $clone_command = 'git clone';
       $fetch_command = 'git fetch';
     } else if ($is_mercurial) {
       $clone_command = 'hg clone';
       $fetch_command = 'hg pull';
     }
 
     $uri_label = 'Repository URI';
     if ($has_local) {
       if ($is_git) {
         $instructions =
           'Enter the URI to clone this repository from. It should look like '.
           '<tt>git@github.com:example/example.git</tt>, '.
           '<tt>ssh://user@host.com/git/example.git</tt>, or '.
           '<tt>file:///local/path/to/repo</tt>';
       } else if ($is_mercurial) {
         $instructions =
           'Enter the URI to clone this repository from. It should look '.
           'something like <tt>ssh://user@host.com/hg/example</tt>';
       }
       $inset->appendChild(
         '<p class="aphront-form-instructions">'.$instructions.'</p>');
     } else if ($is_svn) {
       $instructions =
         'Enter the <strong>Repository Root</strong> for this SVN repository. '.
         'You can figure this out by running <tt>svn info</tt> and looking at '.
         'the value in the <tt>Repository Root</tt> field. It should be a URI '.
         'and look like <tt>http://svn.example.org/svn/</tt> or '.
         '<tt>svn+ssh://svn.example.com/svnroot/</tt>';
       $inset->appendChild(
         '<p class="aphront-form-instructions">'.$instructions.'</p>');
       $uri_label = 'Repository Root';
     }
 
     $inset
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setName('uri')
           ->setLabel($uri_label)
           ->setID('remote-uri')
           ->setValue($repository->getDetail('remote-uri'))
           ->setError($e_uri));
 
     $inset->appendChild(
       '<div class="aphront-form-instructions">'.
         'If you want to connect to this repository over SSH, enter the '.
         'username and private key to use. You can leave these fields blank if '.
         'the repository does not use SSH.'.
       '</div>');
 
     $inset
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setName('ssh-login')
           ->setLabel('SSH User')
           ->setValue($repository->getDetail('ssh-login')))
       ->appendChild(
         id(new AphrontFormTextAreaControl())
           ->setName('ssh-key')
           ->setLabel('SSH Private Key')
           ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)
           ->setValue($repository->getDetail('ssh-key'))
           ->setError($e_ssh_key)
           ->setCaption('Specify the entire private key, <em>or</em>...'))
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setName('ssh-keyfile')
           ->setLabel('SSH Private Key File')
           ->setValue($repository->getDetail('ssh-keyfile'))
           ->setError($e_ssh_keyfile)
           ->setCaption(
             '...specify a path on disk where the daemon should '.
             'look for a private key.'));
 
     if ($has_http_support) {
       $inset
         ->appendChild(
           '<div class="aphront-form-instructions">'.
             'If you want to connect to this repository over HTTP Basic Auth, '.
             'enter the username and password to use. You can leave these '.
             'fields blank if the repository does not use HTTP Basic Auth.'.
           '</div>')
         ->appendChild(
           id(new AphrontFormTextControl())
             ->setName('http-login')
             ->setLabel('HTTP Basic Login')
             ->setValue($repository->getDetail('http-login')))
         ->appendChild(
           id(new AphrontFormPasswordControl())
             ->setName('http-pass')
             ->setLabel('HTTP Basic Password')
             ->setValue($repository->getDetail('http-pass')));
     }
 
     $inset
       ->appendChild(
         '<div class="aphront-form-important">'.
           'To test your authentication configuration, <strong>save this '.
           'form</strong> and then run this script:'.
           '<code>'.
             'phabricator/ $ ./scripts/repository/test_connection.php '.
             phutil_escape_html($repository->getCallsign()).
           '</code>'.
           'This will verify that your configuration is correct and the '.
           'daemons can connect to the remote repository and pull changes '.
           'from it.'.
         '</div>');
 
     $form->appendChild($inset);
 
     $inset = new AphrontFormInsetView();
     $inset->setTitle('Repository Information');
 
     if ($has_local) {
       $inset->appendChild(
         '<p class="aphront-form-instructions">Select a path on local disk '.
         'which the daemons should <tt>'.$clone_command.'</tt> the repository '.
         'into. This must be readable and writable by the daemons, and '.
         'readable by the webserver. The daemons will <tt>'.$fetch_command.
         '</tt> and keep this repository up to date.</p>');
       $inset->appendChild(
         id(new AphrontFormTextControl())
           ->setName('path')
           ->setLabel('Local Path')
           ->setValue($repository->getDetail('local-path'))
           ->setError($e_path));
     } else if ($is_svn) {
       $inset->appendChild(
         '<p class="aphront-form-instructions">If you only want to parse one '.
         'subpath of the repository, specify it here, relative to the '.
         'repository root (e.g., <tt>trunk/</tt> or <tt>projects/wheel/</tt>). '.
         'If you want to parse multiple subdirectories, create a separate '.
         'Phabricator repository for each one.</p>');
       $inset->appendChild(
         id(new AphrontFormTextControl())
           ->setName('svn-subpath')
           ->setLabel('Subpath')
           ->setValue($repository->getDetail('svn-subpath'))
           ->setError($e_path));
     }
 
     if ($has_branch_filter) {
       $branch_filter_str = implode(
         ', ',
         array_keys($repository->getDetail('branch-filter', array())));
       $inset
         ->appendChild(
           id(new AphrontFormTextControl())
             ->setName('branch-filter')
             ->setLabel('Track Only')
             ->setValue($branch_filter_str)
             ->setCaption(
               'Optional list of branches to track. Other branches will be '.
               'completely ignored. If left empty, all branches are tracked. '.
               'Example: <tt>master, release</tt>'));
     }
 
     $inset
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setName('frequency')
           ->setLabel('Pull Frequency')
           ->setValue($repository->getDetail('pull-frequency', 15))
           ->setCaption(
             'Number of seconds daemon should sleep between requests. Larger '.
             'numbers reduce load but also decrease responsiveness.'));
 
     $form->appendChild($inset);
 
     $inset = new AphrontFormInsetView();
     $inset->setTitle('Application Configuration');
 
     if ($has_branches) {
 
       $default_branch_name = null;
       if ($is_mercurial) {
         $default_branch_name = 'default';
       } else if ($is_git) {
         $default_branch_name = 'master';
       }
 
       $inset
         ->appendChild(
           id(new AphrontFormTextControl())
             ->setName('default-branch')
             ->setLabel('Default Branch')
             ->setValue(
               $repository->getDetail(
                 'default-branch',
                 $default_branch_name))
             ->setError($e_branch)
             ->setCaption(
               'Default branch to show in Diffusion.'));
     }
 
     $inset
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setName('default-owners-path')
           ->setLabel('Default Owners Path')
           ->setValue(
             $repository->getDetail(
               'default-owners-path',
               '/'))
           ->setCaption('Default path in Owners tool.'));
 
     $inset
       ->appendChild(
         id(new AphrontFormSelectControl())
           ->setName('herald-disabled')
           ->setLabel('Herald Enabled')
           ->setValue($repository->getDetail('herald-disabled', 0))
           ->setOptions(
             array(
               0 => 'Enabled - Send Email',
               1 => 'Disabled - Do Not Send Email',
             ))
           ->setCaption(
             'You can temporarily disable Herald commit notifications when '.
             'reparsing a repository or importing a new repository.'));
 
     $parsers = id(new PhutilSymbolLoader())
       ->setAncestorClass('PhabricatorRepositoryCommitMessageDetailParser')
       ->selectSymbolsWithoutLoading();
     $parsers = ipull($parsers, 'name', 'name');
 
     $inset
       ->appendChild(
         '<p class="aphront-form-instructions">If you extend the commit '.
         'message format, you can provide a new parser which will extract '.
         'extra information from it when commits are imported. This is an '.
         'advanced feature, and using the default parser will be suitable '.
         'in most cases.</p>')
       ->appendChild(
         id(new AphrontFormSelectControl())
           ->setName('detail-parser')
           ->setLabel('Detail Parser')
           ->setOptions($parsers)
           ->setValue(
             $repository->getDetail(
               'detail-parser',
               'PhabricatorRepositoryDefaultCommitMessageDetailParser')));
 
     if ($is_svn) {
       $inset
         ->appendChild(
           id(new AphrontFormTextControl())
             ->setName('uuid')
             ->setLabel('UUID')
             ->setValue($repository->getUUID())
             ->setCaption('Repository UUID from <tt>svn info</tt>.'));
     }
 
     $form->appendChild($inset);
 
     $form
       ->appendChild(
         id(new AphrontFormSubmitControl())
           ->setValue('Save Configuration'));
 
     $panel = new AphrontPanelView();
     $panel->setHeader('Repository Tracking');
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
 
     $nav = $this->sideNav;
     $nav->appendChild($error_view);
     $nav->appendChild($panel);
 
     return $this->buildStandardPageResponse(
       $nav,
       array(
         'title' => 'Edit Repository Tracking',
       ));
   }
 
 }