diff --git a/conf/default.conf.php b/conf/default.conf.php
index d0b97256f5..229c9e4335 100644
--- a/conf/default.conf.php
+++ b/conf/default.conf.php
@@ -1,348 +1,352 @@
 <?php
 
 /*
  * Copyright 2011 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.
  */
 
 return array(
 
   // The root URI which Phabricator is installed on.
   // Example: "http://phabricator.example.com/"
   'phabricator.base-uri'        => null,
 
   // If you have multiple environments, provide the production environment URI
   // here so that emails, etc., generated in development/sandbox environments
   // contain the right links.
   'phabricator.production-uri'  => null,
 
+  // Setting this to 'true' will invoke a special setup mode which helps guide
+  // you through setting up Phabricator.
+  'phabricator.setup'           => false,
+
   // The default PHID for users who haven't uploaded a profile image. It should
   // be 50x50px.
   'user.default-profile-image-phid' => 'PHID-FILE-4d61229816cfe6f2b2a3',
 
 // -- Access Control -------------------------------------------------------- //
 
   // Phabricator users have one of three access levels: "anyone", "verified",
   // or "admin". "anyone" means every user, including users who do not have
   // accounts or are not logged into the system. "verified" is users who have
   // accounts, are logged in, and have satisfied whatever verification steps
   // the configuration requires (e.g., email verification and/or manual
   // approval). "admin" is verified users with the "administrator" flag set.
 
   // These configuration options control which access level is required to read
   // data from Phabricator (e.g., view revisions and comments in Differential)
   // and write data to Phabricator (e.g., upload files and create diffs). By
   // default they are both set to "verified", meaning only verified user
   // accounts can interact with the system in any meaningful way.
 
   // If you are configuring an install for an open source project, you may
   // want to reduce the "phabricator.read-access" requirement to "anyone". This
   // will allow anyone to browse Phabricator content, even without logging in.
 
   // Alternatively, you could raise the "phabricator.write-access" requirement
   // to "admin", effectively creating a read-only install.
 
 
   // Controls the minimum access level required to read data from Phabricator
   // (e.g., view revisions in Differential). Allowed values are "anyone",
   // "verified", or "admin". Note that "anyone" includes users who are not
   // logged in! You should leave this at 'verified' unless you want your data
   // to be publicly readable (e.g., you are developing open source software).
   'phabricator.read-access'     => 'verified',
 
   // Controls the minimum access level required to write data to Phabricator
   // (e.g., create new revisions in Differential). Allowed values are
   // "verified" or "admin". Setting this to "admin" will effectively create a
   // read-only install.
   'phabricator.write-access'    => 'verified',
 
 
 // -- DarkConsole ----------------------------------------------------------- //
 
   // DarkConsole is a administrative debugging/profiling tool built into
   // Phabricator. You can leave it disabled unless you're developing against
   // Phabricator.
 
   // Determines whether or not DarkConsole is available. DarkConsole exposes
   // some data like queries and stack traces, so you should be careful about
   // turning it on in production (although users can not normally see it, even
   // if the deployment configuration enables it).
-  'darkconsole.enabled'         => true,
+  'darkconsole.enabled'         => false,
 
   // Always enable DarkConsole, even for logged out users. This potentially
   // exposes sensitive information to users, so make sure untrusted users can
   // not access an install running in this mode. You should definitely leave
   // this off in production. It is only really useful for using DarkConsole
   // utilties to debug or profile logged-out pages. You must set
   // 'darkconsole.enabled' to use this option.
   'darkconsole.always-on'       => false,
 
 
   // Allows you to mask certain configuration values from appearing in the
   // "Config" tab of DarkConsole.
   'darkconsole.config-mask'     => array(
     'mysql.pass',
     'amazon-ses.secret-key',
     'recaptcha.private-key',
     'phabricator.csrf-key',
     'facebook.application-secret',
     'github.application-secret',
   ),
 
 // --  MySQL  --------------------------------------------------------------- //
 
   // The username to use when connecting to MySQL.
   'mysql.user' => 'root',
 
   // The password to use when connecting to MySQL.
   'mysql.pass' => '',
 
   // The MySQL server to connect to.
   'mysql.host' => 'localhost',
 
 // -- Email ----------------------------------------------------------------- //
 
   // Some Phabricator tools send email notifications, e.g. when Differential
   // revisions are updated or Maniphest tasks are changed. These options allow
   // you to configure how email is delivered.
 
   // You can test your mail setup by going to "MetaMTA" in the web interface,
   // clicking "Send New Message", and then composing a message.
 
   // Default address to send mail "From".
   'metamta.default-address'     => 'noreply@example.com',
 
   // Domain used to generate Message-IDs.
   'metamta.domain'              => 'example.com',
 
   // When a user takes an action which generates an email notification (like
   // commenting on a Differential revision), Phabricator can either send that
   // mail "From" the user's email address (like "alincoln@logcabin.com") or
   // "From" the 'metamta.default-address' address. The user experience is
   // generally better if Phabricator uses the user's real address as the "From"
   // since the messages are easier to organize when they appear in mail clients,
   // but this will only work if the server is authorized to send email on behalf
   // of the "From" domain. Practically, this means:
   //    - If you are doing an install for Example Corp and all the users will
   //      have corporate @corp.example.com addresses and any hosts Phabricator
   //      is running on are authorized to send email from corp.example.com,
   //      you can enable this to make the user experience a little better.
   //    - If you are doing an install for an open source project and your
   //      users will be registering via Facebook and using personal email
   //      addresses, you MUST NOT enable this or virtually all of your outgoing
   //      email will vanish into SFP blackholes.
   //    - If your install is anything else, you're much safer leaving this
   //      off since the risk in turning it on is that your outgoing mail will
   //      mostly never arrive.
   'metamta.can-send-as-user'    => false,
 
   // Adapter class to use to transmit mail to the MTA. The default uses
   // PHPMailerLite, which will invoke PHP's mail() function. This is appropriate
   // if mail() actually works on your host, but if you haven't configured mail
   // it may not be so great. You can also use Amazon SES, by changing this to
   // 'PhabricatorMailImplementationAmazonSESAdapter', signing up for SES, and
   // filling in your 'amazon-ses.access-key' and 'amazon-ses.secret-key' below.
   'metamta.mail-adapter'        =>
     'PhabricatorMailImplementationPHPMailerLiteAdapter',
 
   // When email is sent, try to hand it off to the MTA immediately. This may
   // be worth disabling if your MTA infrastructure is slow or unreliable. If you
   // disable this option, you must run the 'metamta_mta.php' daemon or mail
   // won't be handed off to the MTA. If you're using Amazon SES it can be a
   // little slugish sometimes so it may be worth disabling this and moving to
   // the daemon after you've got your install up and running. If you have a
   // properly configured local MTA it should not be necessary to disable this.
   'metamta.send-immediately'    => true,
 
   // If you're using Amazon SES to send email, provide your AWS access key
   // and AWS secret key here. To set up Amazon SES with Phabricator, you need
   // to:
   //  - Make sure 'metamta.mail-adapter' is set to:
   //    "PhabricatorMailImplementationAmazonSESAdapter"
   //  - Make sure 'metamta.can-send-as-user' is false.
   //  - Make sure 'metamta.default-address' is configured to something sensible.
   //  - Make sure 'metamta.default-address' is a validated SES "From" address.
   'amazon-ses.access-key'       =>  null,
   'amazon-ses.secret-key'       =>  null,
 
 
 // -- Auth ------------------------------------------------------------------ //
 
   // Can users login with a username/password, or by following the link from
   // a password reset email? You can disable this and configure one or more
   // OAuth providers instead.
   'auth.password-auth-enabled'  => true,
 
 
 // -- Accounts -------------------------------------------------------------- //
 
   // Is basic account information (email, real name, profile picture) editable?
   // If you set up Phabricator to automatically synchronize account information
   // from some other authoritative system, you can disable this to ensure
   // information remains consistent across both systems.
   'account.editable'            => true,
 
 
 // --  Facebook  ------------------------------------------------------------ //
 
   // Can users use Facebook credentials to login to Phabricator?
   'facebook.auth-enabled'       => false,
 
   // Can users use Facebook credentials to create new Phabricator accounts?
   'facebook.registration-enabled' => true,
 
   // Are Facebook accounts permanently linked to Phabricator accounts, or can
   // the user unlink them?
   'facebook.auth-permanent'     => false,
 
   // The Facebook "Application ID" to use for Facebook API access.
   'facebook.application-id'     => null,
 
   // The Facebook "Application Secret" to use for Facebook API access.
   'facebook.application-secret' => null,
 
 
 // -- Github ---------------------------------------------------------------- //
 
   // Can users use Github credentials to login to Phabricator?
   'github.auth-enabled'         => false,
 
   // Can users use Github credentials to create new Phabricator accounts?
   'github.registration-enabled' => true,
 
   // Are Github accounts permanently linked to Phabricator accounts, or can
   // the user unlink them?
   'github.auth-permanent'       => false,
 
   // The Github "Client ID" to use for Github API access.
   'github.application-id'       => null,
 
   // The Github "Secret" to use for Github API access.
   'github.application-secret'   => null,
 
 
 // -- Recaptcha ------------------------------------------------------------- //
 
   // Is Recaptcha enabled? If disabled, captchas will not appear.
   'recaptcha.enabled'           => false,
 
   // Your Recaptcha public key, obtained from Recaptcha.
   'recaptcha.public-key'        => null,
 
   // Your Recaptcha private key, obtained from Recaptcha.
   'recaptcha.private-key'       => null,
 
 
 // -- Misc ------------------------------------------------------------------ //
 
   // This is hashed with other inputs to generate CSRF tokens. If you want, you
   // can change it to some other string which is unique to your install. This
   // will make your install more secure in a vague, mostly theoretical way. But
   // it will take you like 3 seconds of mashing on your keyboard to set it up so
   // you might as well.
   'phabricator.csrf-key'        => '0b7ec0592e0a2829d8b71df2fa269b2c6172eca3',
 
   // This is hashed with other inputs to generate mail tokens. If you want, you
   // can change it to some other string which is unique to your install. In
   // particular, you will want to do this if you accidentally send a bunch of
   // mail somewhere you shouldn't have, to invalidate all old reply-to
   // addresses.
   'phabricator.mail-key'        => '5ce3e7e8787f6e40dfae861da315a5cdf1018f12',
 
   // Version string displayed in the footer. You probably should leave this
   // alone.
   'phabricator.version'         => 'UNSTABLE',
 
   // PHP requires that you set a timezone in your php.ini before using date
   // functions, or it will emit a warning. If this isn't possible (for instance,
   // because you are using HPHP) you can set some valid constant for
   // date_default_timezone_set() here and Phabricator will set it on your
   // behalf, silencing the warning.
   'phabricator.timezone'        => null,
 
 
   // Phabricator can highlight PHP by default, but if you want syntax
   // highlighting for other languages you should install the python package
   // 'Pygments', make sure the 'pygmentize' script is available in the
   // $PATH of the webserver, and then enable this.
   'pygments.enabled'            => false,
 
 
 // -- Files ----------------------------------------------------------------- //
 
   // Lists which uploaded file types may be viewed in the browser. If a file
   // has a mime type which does not appear in this list, it will always be
   // downloaded instead of displayed. This is a security consideration: if a
   // user uploads a file of type "text/html" and it is displayed as
   // "text/html", they can eaily execute XSS attacks. This is also a usability
   // consideration, since browsers tend to freak out when viewing enormous
   // binary files.
   //
   // The keys in this array are viewable mime types; the values are the mime
   // types they will be delivered as when they are viewed in the browser.
   'files.viewable-mime-types' => array(
     'image/jpeg'  => 'image/jpeg',
     'image/jpg'   => 'image/jpg',
     'image/png'   => 'image/png',
     'image/gif'   => 'image/gif',
     'text/plain'  => 'text/plain; charset=utf-8',
   ),
 
   // Phabricator can proxy images from other servers so you can paste the URI
   // to a funny picture of a cat into the comment box and have it show up as an
   // image. However, this means the webserver Phabricator is running on will
   // make HTTP requests to arbitrary URIs. If the server has access to internal
   // resources, this could be a security risk. You should only enable it if you
   // are installed entirely a VPN and VPN access is required to access
   // Phabricator, or if the webserver has no special access to anything. If
   // unsure, it is safer to leave this disabled.
   'files.enable-proxy' => false,
 
 // -- Differential ---------------------------------------------------------- //
 
   'differential.revision-custom-detail-renderer'  => null,
 
   'phabricator.enable-reply-handling' => false,
   'differential.replyhandler' => 'DifferentialReplyHandler',
 
 
 // -- Maniphest ------------------------------------------------------------- //
 
   'maniphest.enabled' => true,
 
 // -- Customization --------------------------------------------------------- //
 
   // Paths to additional phutil libraries to load.
   'load-libraries' => array(),
 
   'aphront.default-application-configuration-class' =>
     'AphrontDefaultApplicationConfiguration',
 
   'controller.oauth-registration' =>
     'PhabricatorOAuthDefaultRegistrationController',
 
 
   // Directory that phd (the Phabricator daemon control script) should use to
   // track running daemons.
   'phd.pid-directory' => '/var/tmp/phd',
 
   // This value is an input to the hash function when building resource hashes.
   // It has no security value, but if you accidentally poison user caches (by
   // pushing a bad patch or having something go wrong with a CDN, e.g.) you can
   // change this to something else and rebuild the Celerity map to break user
   // caches. Unless you are doing Celerity development, it is exceptionally
   // unlikely that you need to modify this.
   'celerity.resource-hash' => 'd9455ea150622ee044f7931dabfa52aa',
 
 );
diff --git a/conf/development.conf.php b/conf/development.conf.php
index 85673eab81..51a1c1a6f0 100644
--- a/conf/development.conf.php
+++ b/conf/development.conf.php
@@ -1,22 +1,23 @@
 <?php
 
 /*
  * Copyright 2011 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.
  */
 
 return array(
 
+  'darkconsole.enabled' => true,
 
 ) + phabricator_read_config_file('default');
diff --git a/conf/production.conf.php b/conf/production.conf.php
index f4dd87dcb5..7228521c76 100644
--- a/conf/production.conf.php
+++ b/conf/production.conf.php
@@ -1,24 +1,22 @@
 <?php
 
 /*
  * Copyright 2011 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.
  */
 
 return array(
 
-  'darkconsole.enabled' => false,
-
 ) + phabricator_read_config_file('default');
 
diff --git a/conf/setup.conf.php b/conf/setup.conf.php
deleted file mode 100644
index 85673eab81..0000000000
--- a/conf/setup.conf.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-
-/*
- * Copyright 2011 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.
- */
-
-return array(
-
-
-) + phabricator_read_config_file('default');
diff --git a/resources/sql/patches/037.setuptest.sql b/resources/sql/patches/037.setuptest.sql
new file mode 100644
index 0000000000..e0ac49d1ec
--- /dev/null
+++ b/resources/sql/patches/037.setuptest.sql
@@ -0,0 +1 @@
+SELECT 1;
diff --git a/scripts/sql/upgrade_schema.php b/scripts/sql/upgrade_schema.php
index 5de9a5711a..39b589a6dc 100755
--- a/scripts/sql/upgrade_schema.php
+++ b/scripts/sql/upgrade_schema.php
@@ -1,185 +1,164 @@
 #!/usr/bin/env php
 <?php
 
 /*
  * Copyright 2011 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.
  */
 
 $root = dirname(dirname(dirname(__FILE__)));
 require_once $root.'/scripts/__init_script__.php';
 require_once $root.'/scripts/__init_env__.php';
 
 phutil_require_module('phutil', 'console');
+phutil_require_module('phabricator', 'infrastructure/setup/sql');
 
 define('SCHEMA_VERSION_TABLE_NAME', 'schema_version');
 
 $options = getopt('v:u:p:') + array(
   'v' => null,
   'u' => null,
   'p' => null,
 );
 
 if ($options['v'] && !is_numeric($options['v'])) {
   usage();
 }
 
 echo phutil_console_wrap(
   "Before running this script, you should take down the Phabricator web ".
   "interface and stop any running Phabricator daemons.");
 
 if (!phutil_console_confirm('Are you ready to continue?')) {
   echo "Cancelled.\n";
   exit(1);
 }
 
 // Use always the version from the commandline if it is defined
 $next_version = isset($options['v']) ? (int)$options['v'] : null;
 
 if ($options['u']) {
   $conn_user = $options['u'];
   $conn_pass = $options['p'];
 } else {
   $conn_user = PhabricatorEnv::getEnvConfig('mysql.user');
   $conn_pass = PhabricatorEnv::getEnvConfig('mysql.pass');
 }
 $conn_host = PhabricatorEnv::getEnvConfig('mysql.host');
 
 $conn = new AphrontMySQLDatabaseConnection(
   array(
     'user'      => $conn_user,
     'pass'      => $conn_pass,
     'host'      => $conn_host,
     'database'  => null,
   ));
 
 try {
 
   $create_sql = <<<END
   CREATE DATABASE IF NOT EXISTS `phabricator_meta_data`;
 END;
   queryfx($conn, $create_sql);
 
   $create_sql = <<<END
   CREATE TABLE IF NOT EXISTS phabricator_meta_data.`schema_version` (
     `version` INTEGER not null
   );
 END;
   queryfx($conn, $create_sql);
 
   // Get the version only if commandline argument wasn't given
   if ($next_version === null) {
     $version = queryfx_one(
       $conn,
       'SELECT * FROM phabricator_meta_data.%T',
       SCHEMA_VERSION_TABLE_NAME);
 
     if (!$version) {
       print "*** No version information in the database ***\n";
       print "*** Give the first patch version which to  ***\n";
       print "*** apply as the command line argument     ***\n";
       exit(-1);
     }
 
     $next_version = $version['version'] + 1;
   }
 
-  // Find the patch files
-  $patches_dir = $root.'/resources/sql/patches/';
-  $finder = id(new FileFinder($patches_dir))
-    ->withSuffix('sql');
-  $results = $finder->find();
-
-  $patches = array();
-  foreach ($results as $r) {
-    $matches = array();
-    if (preg_match('/(\d+)\..*\.sql$/', $r, $matches)) {
-      $patches[] = array('version' => (int)$matches[1],
-                         'file' => $r);
-    } else {
-      print
-        "*** WARNING : File {$r} does not follow the normal naming ".
-        "convention. ***\n";
-    }
-  }
-
-  // Files are in some 'random' order returned by the operating system
-  // We need to apply them in proper order
-  $patches = isort($patches, 'version');
+  $patches = PhabricatorSQLPatchList::getPatchList();
 
   $patch_applied = false;
   foreach ($patches as $patch) {
     if ($patch['version'] < $next_version) {
       continue;
     }
 
-    print "Applying patch {$patch['file']}\n";
-
-    $path = Filesystem::resolvePath($patches_dir.$patch['file']);
+    $short_name = basename($patch['path']);
+    print "Applying patch {$short_name}...\n";
 
     list($stdout, $stderr) = execx(
       "mysql --user=%s --password=%s --host=%s < %s",
       $conn_user,
       $conn_pass,
       $conn_host,
-      $path);
+      $patch['path']);
 
     if ($stderr) {
       print $stderr;
       exit(-1);
     }
 
     // Patch was successful, update the db with the latest applied patch version
     // 'DELETE' and 'INSERT' instead of update, because the table might be empty
     queryfx(
       $conn,
       'DELETE FROM phabricator_meta_data.%T',
       SCHEMA_VERSION_TABLE_NAME);
     queryfx(
       $conn,
       'INSERT INTO phabricator_meta_data.%T VALUES (%d)',
       SCHEMA_VERSION_TABLE_NAME,
       $patch['version']);
 
     $patch_applied = true;
   }
 
   if (!$patch_applied) {
     print "Your database is already up-to-date.\n";
   }
 
 } catch (AphrontQueryAccessDeniedException $ex) {
   echo
     "ACCESS DENIED\n".
     "The user '{$conn_user}' does not have sufficient MySQL privileges to\n".
     "execute the schema upgrade. Use the -u and -p flags to run as a user\n".
     "with more privileges (e.g., root).".
     "\n\n".
     "EXCEPTION:\n".
     $ex->getMessage().
     "\n\n";
   exit(1);
 }
 
 function usage() {
   echo
     "usage: upgrade_schema.php [-v version] [-u user -p pass]".
     "\n\n".
     "Run 'upgrade_schema.php -v 12' to apply all patches starting from ".
     "version 12.\n".
     "Run 'upgrade_schema.php -u root -p hunter2' to override the configured ".
     "default user.\n";
   exit(1);
 }
 
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 571c13726f..d5ff859d10 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,890 +1,892 @@
 <?php
 
 /**
  * This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
  * @generated
  */
 
 phutil_register_library_map(array(
   'class' =>
   array(
     'Aphront304Response' => 'aphront/response/304',
     'Aphront400Response' => 'aphront/response/400',
     'Aphront404Response' => 'aphront/response/404',
     'AphrontAjaxResponse' => 'aphront/response/ajax',
     'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
     'AphrontController' => 'aphront/controller',
     'AphrontCrumbsView' => 'view/layout/crumbs',
     'AphrontDatabaseConnection' => 'storage/connection/base',
     'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
     'AphrontDefaultApplicationController' => 'aphront/default/controller',
     'AphrontDialogResponse' => 'aphront/response/dialog',
     'AphrontDialogView' => 'view/dialog',
     'AphrontErrorView' => 'view/form/error',
     'AphrontException' => 'aphront/exception/base',
     'AphrontFileResponse' => 'aphront/response/file',
     'AphrontFormCheckboxControl' => 'view/form/control/checkbox',
     'AphrontFormControl' => 'view/form/control/base',
     'AphrontFormDividerControl' => 'view/form/control/divider',
     'AphrontFormFileControl' => 'view/form/control/file',
     'AphrontFormMarkupControl' => 'view/form/control/markup',
     'AphrontFormPasswordControl' => 'view/form/control/password',
     'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha',
     'AphrontFormSelectControl' => 'view/form/control/select',
     'AphrontFormStaticControl' => 'view/form/control/static',
     'AphrontFormSubmitControl' => 'view/form/control/submit',
     'AphrontFormTextAreaControl' => 'view/form/control/textarea',
     'AphrontFormTextControl' => 'view/form/control/text',
     'AphrontFormToggleButtonsControl' => 'view/form/control/togglebuttons',
     'AphrontFormTokenizerControl' => 'view/form/control/tokenizer',
     'AphrontFormView' => 'view/form/base',
     'AphrontHeadsupActionListView' => 'view/layout/headsup/actionlist',
     'AphrontHeadsupActionView' => 'view/layout/headsup/action',
     'AphrontIsolatedDatabaseConnection' => 'storage/connection/isolated',
     'AphrontIsolatedDatabaseConnectionTestCase' => 'storage/connection/isolated/__tests__',
     'AphrontListFilterView' => 'view/layout/listfilter',
     'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql',
     'AphrontNullView' => 'view/null',
     'AphrontPageView' => 'view/page/base',
     'AphrontPagerView' => 'view/control/pager',
     'AphrontPanelView' => 'view/layout/panel',
     'AphrontQueryAccessDeniedException' => 'storage/exception/accessdenied',
     'AphrontQueryConnectionException' => 'storage/exception/connection',
     'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost',
     'AphrontQueryCountException' => 'storage/exception/count',
     'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey',
     'AphrontQueryException' => 'storage/exception/base',
     'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing',
     'AphrontQueryParameterException' => 'storage/exception/parameter',
     'AphrontQueryRecoverableException' => 'storage/exception/recoverable',
     'AphrontRedirectException' => 'aphront/exception/redirect',
     'AphrontRedirectResponse' => 'aphront/response/redirect',
     'AphrontRequest' => 'aphront/request',
     'AphrontRequestFailureView' => 'view/page/failure',
     'AphrontResponse' => 'aphront/response/base',
     'AphrontSideNavView' => 'view/layout/sidenav',
     'AphrontTableView' => 'view/control/table',
     'AphrontTokenizerTemplateView' => 'view/control/tokenizer',
     'AphrontTypeaheadTemplateView' => 'view/control/typeahead',
     'AphrontURIMapper' => 'aphront/mapper',
     'AphrontView' => 'view/base',
     'AphrontWebpageResponse' => 'aphront/response/webpage',
     'CelerityAPI' => 'infrastructure/celerity/api',
     'CelerityResourceController' => 'infrastructure/celerity/controller',
     'CelerityResourceMap' => 'infrastructure/celerity/map',
     'CelerityStaticResourceResponse' => 'infrastructure/celerity/response',
     'ConduitAPIMethod' => 'applications/conduit/method/base',
     'ConduitAPIRequest' => 'applications/conduit/protocol/request',
     'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect',
     'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping',
     'ConduitAPI_daemon_launched_Method' => 'applications/conduit/method/daemon/launched',
     'ConduitAPI_daemon_log_Method' => 'applications/conduit/method/daemon/log',
     'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff',
     'ConduitAPI_differential_createrevision_Method' => 'applications/conduit/method/differential/createrevision',
     'ConduitAPI_differential_find_Method' => 'applications/conduit/method/differential/find',
     'ConduitAPI_differential_getalldiffs_Method' => 'applications/conduit/method/differential/getalldiffs',
     'ConduitAPI_differential_getcommitmessage_Method' => 'applications/conduit/method/differential/getcommitmessage',
     'ConduitAPI_differential_getcommitpaths_Method' => 'applications/conduit/method/differential/getcommitpaths',
     'ConduitAPI_differential_getdiff_Method' => 'applications/conduit/method/differential/getdiff',
     'ConduitAPI_differential_getrevision_Method' => 'applications/conduit/method/differential/getrevision',
     'ConduitAPI_differential_getrevisionfeedback_Method' => 'applications/conduit/method/differential/getrevisionfeedback',
     'ConduitAPI_differential_markcommitted_Method' => 'applications/conduit/method/differential/markcommitted',
     'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/conduit/method/differential/parsecommitmessage',
     'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty',
     'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision',
     'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'applications/conduit/method/differential/updatetaskrevisionassoc',
     'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits',
     'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
     'ConduitAPI_path_getowners_Method' => 'applications/conduit/method/path/getowners',
     'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
     'ConduitAPI_user_whoami_Method' => 'applications/conduit/method/user/whoami',
     'ConduitException' => 'applications/conduit/protocol/exception',
     'DarkConsole' => 'aphront/console/api',
     'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
     'DarkConsoleController' => 'aphront/console/controller',
     'DarkConsoleCore' => 'aphront/console/core',
     'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog',
     'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api',
     'DarkConsolePlugin' => 'aphront/console/plugin/base',
     'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request',
     'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services',
     'DarkConsoleServicesPluginAPI' => 'aphront/console/plugin/services/api',
     'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof',
     'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api',
     'DatabaseConfigurationProvider' => 'applications/base/storage/configuration',
     'DifferentialAction' => 'applications/differential/constants/action',
     'DifferentialAddCommentView' => 'applications/differential/view/addcomment',
     'DifferentialAttachController' => 'applications/differential/controller/attach',
     'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
     'DifferentialChangeType' => 'applications/differential/constants/changetype',
     'DifferentialChangeset' => 'applications/differential/storage/changeset',
     'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview',
     'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview',
     'DifferentialChangesetParser' => 'applications/differential/parser/changeset',
     'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview',
     'DifferentialComment' => 'applications/differential/storage/comment',
     'DifferentialCommentEditor' => 'applications/differential/editor/comment',
     'DifferentialCommentMail' => 'applications/differential/mail/comment',
     'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview',
     'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave',
     'DifferentialCommitMessage' => 'applications/differential/parser/commitmessage',
     'DifferentialCommitMessageData' => 'applications/differential/data/commitmessage',
     'DifferentialCommitMessageParserException' => 'applications/differential/parser/commitmessage/exception',
     'DifferentialController' => 'applications/differential/controller/base',
     'DifferentialDAO' => 'applications/differential/storage/base',
     'DifferentialDiff' => 'applications/differential/storage/diff',
     'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent',
     'DifferentialDiffCreateController' => 'applications/differential/controller/diffcreate',
     'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty',
     'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
     'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
     'DifferentialExceptionMail' => 'applications/differential/mail/exception',
     'DifferentialHunk' => 'applications/differential/storage/hunk',
     'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment',
     'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit',
     'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview',
     'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment',
     'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
     'DifferentialMail' => 'applications/differential/mail/base',
     'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup',
     'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff',
     'DifferentialReplyHandler' => 'applications/differential/replyhandler',
     'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
     'DifferentialRevision' => 'applications/differential/storage/revision',
     'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist',
     'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment',
     'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem',
     'DifferentialRevisionDetailRenderer' => 'applications/differential/controller/customrenderer',
     'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail',
     'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit',
     'DifferentialRevisionEditor' => 'applications/differential/editor/revision',
     'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
     'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
     'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
     'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
     'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
     'DifferentialSubscribeController' => 'applications/differential/controller/subscribe',
     'DifferentialTasksAttacher' => 'applications/differential/tasks',
     'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
     'DifferentialViewTime' => 'applications/differential/storage/viewtime',
     'DiffusionBranchInformation' => 'applications/diffusion/data/branch',
     'DiffusionBranchQuery' => 'applications/diffusion/query/branch/base',
     'DiffusionBranchTableView' => 'applications/diffusion/view/branchtable',
     'DiffusionBrowseController' => 'applications/diffusion/controller/browse',
     'DiffusionBrowseFileController' => 'applications/diffusion/controller/file',
     'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base',
     'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable',
     'DiffusionChangeController' => 'applications/diffusion/controller/change',
     'DiffusionCommitChangeTableView' => 'applications/diffusion/view/commitchangetable',
     'DiffusionCommitController' => 'applications/diffusion/controller/commit',
     'DiffusionController' => 'applications/diffusion/controller/base',
     'DiffusionDiffController' => 'applications/diffusion/controller/diff',
     'DiffusionDiffQuery' => 'applications/diffusion/query/diff/base',
     'DiffusionFileContent' => 'applications/diffusion/data/filecontent',
     'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base',
     'DiffusionGitBranchQuery' => 'applications/diffusion/query/branch/git',
     'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git',
     'DiffusionGitDiffQuery' => 'applications/diffusion/query/diff/git',
     'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/git',
     'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/git',
     'DiffusionGitLastModifiedQuery' => 'applications/diffusion/query/lastmodified/git',
     'DiffusionGitPathIDQuery' => 'applications/diffusion/query/pathid/base',
     'DiffusionGitRequest' => 'applications/diffusion/request/git',
     'DiffusionHistoryController' => 'applications/diffusion/controller/history',
     'DiffusionHistoryQuery' => 'applications/diffusion/query/history/base',
     'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable',
     'DiffusionHomeController' => 'applications/diffusion/controller/home',
     'DiffusionLastModifiedController' => 'applications/diffusion/controller/lastmodified',
     'DiffusionLastModifiedQuery' => 'applications/diffusion/query/lastmodified/base',
     'DiffusionPathChange' => 'applications/diffusion/data/pathchange',
     'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/base',
     'DiffusionPathCompleteController' => 'applications/diffusion/controller/pathcomplete',
     'DiffusionPathValidateController' => 'applications/diffusion/controller/pathvalidate',
     'DiffusionRepositoryController' => 'applications/diffusion/controller/repository',
     'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath',
     'DiffusionRequest' => 'applications/diffusion/request/base',
     'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/svn',
     'DiffusionSvnDiffQuery' => 'applications/diffusion/query/diff/svn',
     'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/svn',
     'DiffusionSvnHistoryQuery' => 'applications/diffusion/query/history/svn',
     'DiffusionSvnLastModifiedQuery' => 'applications/diffusion/query/lastmodified/svn',
     'DiffusionSvnRequest' => 'applications/diffusion/request/svn',
     'DiffusionView' => 'applications/diffusion/view/base',
     'HeraldAction' => 'applications/herald/storage/action',
     'HeraldActionConfig' => 'applications/herald/config/action',
     'HeraldApplyTranscript' => 'applications/herald/storage/transcript/apply',
     'HeraldCommitAdapter' => 'applications/herald/adapter/commit',
     'HeraldCondition' => 'applications/herald/storage/condition',
     'HeraldConditionConfig' => 'applications/herald/config/condition',
     'HeraldConditionTranscript' => 'applications/herald/storage/transcript/condition',
     'HeraldContentTypeConfig' => 'applications/herald/config/contenttype',
     'HeraldController' => 'applications/herald/controller/base',
     'HeraldDAO' => 'applications/herald/storage/base',
     'HeraldDeleteController' => 'applications/herald/controller/delete',
     'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/differential',
     'HeraldDryRunAdapter' => 'applications/herald/adapter/dryrun',
     'HeraldEffect' => 'applications/herald/engine/effect',
     'HeraldEngine' => 'applications/herald/engine/engine',
     'HeraldFieldConfig' => 'applications/herald/config/field',
     'HeraldHomeController' => 'applications/herald/controller/home',
     'HeraldInvalidConditionException' => 'applications/herald/engine/engine/exception',
     'HeraldInvalidFieldException' => 'applications/herald/engine/engine/exception',
     'HeraldNewController' => 'applications/herald/controller/new',
     'HeraldObjectAdapter' => 'applications/herald/adapter/base',
     'HeraldObjectTranscript' => 'applications/herald/storage/transcript/object',
     'HeraldRecursiveConditionsException' => 'applications/herald/engine/engine/exception',
     'HeraldRule' => 'applications/herald/storage/rule',
     'HeraldRuleController' => 'applications/herald/controller/rule',
     'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule',
     'HeraldTestConsoleController' => 'applications/herald/controller/test',
     'HeraldTranscript' => 'applications/herald/storage/transcript/base',
     'HeraldTranscriptController' => 'applications/herald/controller/transcript',
     'HeraldTranscriptListController' => 'applications/herald/controller/transcriptlist',
     'HeraldValueTypeConfig' => 'applications/herald/config/valuetype',
     'Javelin' => 'infrastructure/javelin/api',
     'LiskDAO' => 'storage/lisk/dao',
     'LiskIsolationTestCase' => 'storage/lisk/dao/__tests__',
     'LiskIsolationTestDAO' => 'storage/lisk/dao/__tests__',
     'LiskIsolationTestDAOException' => 'storage/lisk/dao/__tests__',
     'ManiphestController' => 'applications/maniphest/controller/base',
     'ManiphestDAO' => 'applications/maniphest/storage/base',
     'ManiphestTask' => 'applications/maniphest/storage/task',
     'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail',
     'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit',
     'ManiphestTaskListController' => 'applications/maniphest/controller/tasklist',
     'ManiphestTaskListView' => 'applications/maniphest/view/tasklist',
     'ManiphestTaskPriority' => 'applications/maniphest/constants/priority',
     'ManiphestTaskSelectorSearchController' => 'applications/maniphest/controller/taskselectorsearch',
     'ManiphestTaskStatus' => 'applications/maniphest/constants/status',
     'ManiphestTaskSummaryView' => 'applications/maniphest/view/tasksummary',
     'ManiphestTransaction' => 'applications/maniphest/storage/transaction',
     'ManiphestTransactionDetailView' => 'applications/maniphest/view/transactiondetail',
     'ManiphestTransactionEditor' => 'applications/maniphest/editor/transaction',
     'ManiphestTransactionListView' => 'applications/maniphest/view/transactionlist',
     'ManiphestTransactionPreviewController' => 'applications/maniphest/controller/transactionpreview',
     'ManiphestTransactionSaveController' => 'applications/maniphest/controller/transactionsave',
     'ManiphestTransactionType' => 'applications/maniphest/constants/transactiontype',
     'Phabricator404Controller' => 'applications/base/controller/404',
     'PhabricatorAuthController' => 'applications/auth/controller/base',
     'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
     'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
     'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console',
     'PhabricatorConduitController' => 'applications/conduit/controller/base',
     'PhabricatorConduitDAO' => 'applications/conduit/storage/base',
     'PhabricatorConduitLogController' => 'applications/conduit/controller/log',
     'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog',
     'PhabricatorController' => 'applications/base/controller/base',
     'PhabricatorDaemon' => 'infrastructure/daemon/base',
     'PhabricatorDaemonCombinedLogController' => 'applications/daemon/controller/combined',
     'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/console',
     'PhabricatorDaemonControl' => 'infrastructure/daemon/control',
     'PhabricatorDaemonController' => 'applications/daemon/controller/base',
     'PhabricatorDaemonDAO' => 'infrastructure/daemon/storage/base',
     'PhabricatorDaemonLog' => 'infrastructure/daemon/storage/log',
     'PhabricatorDaemonLogEvent' => 'infrastructure/daemon/storage/event',
     'PhabricatorDaemonLogEventsView' => 'applications/daemon/view/daemonlogevents',
     'PhabricatorDaemonLogListController' => 'applications/daemon/controller/loglist',
     'PhabricatorDaemonLogListView' => 'applications/daemon/view/daemonloglist',
     'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/logview',
     'PhabricatorDaemonReference' => 'infrastructure/daemon/control/reference',
     'PhabricatorDaemonTimelineConsoleController' => 'applications/daemon/controller/timeline',
     'PhabricatorDaemonTimelineEventController' => 'applications/daemon/controller/timelineevent',
     'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
     'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
     'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
     'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist',
     'PhabricatorDirectoryController' => 'applications/directory/controller/base',
     'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
     'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
     'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
     'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
     'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist',
     'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
     'PhabricatorDraft' => 'applications/draft/storage/draft',
     'PhabricatorDraftDAO' => 'applications/draft/storage/base',
     'PhabricatorEditPreferencesController' => 'applications/preferences/controller/edit',
     'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
     'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
     'PhabricatorEnv' => 'infrastructure/env',
     'PhabricatorFile' => 'applications/files/storage/file',
     'PhabricatorFileController' => 'applications/files/controller/base',
     'PhabricatorFileDAO' => 'applications/files/storage/base',
     'PhabricatorFileImageMacro' => 'applications/files/storage/imagemacro',
     'PhabricatorFileListController' => 'applications/files/controller/list',
     'PhabricatorFileMacroDeleteController' => 'applications/files/controller/macrodelete',
     'PhabricatorFileMacroEditController' => 'applications/files/controller/macroedit',
     'PhabricatorFileMacroListController' => 'applications/files/controller/macrolist',
     'PhabricatorFileProxyController' => 'applications/files/controller/proxy',
     'PhabricatorFileProxyImage' => 'applications/files/storage/proxyimage',
     'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob',
     'PhabricatorFileURI' => 'applications/files/uri',
     'PhabricatorFileUploadController' => 'applications/files/controller/upload',
     'PhabricatorFileViewController' => 'applications/files/controller/view',
     'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing',
     'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector',
     'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/javelin',
     'PhabricatorLintEngine' => 'infrastructure/lint/engine',
     'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
     'PhabricatorLoginController' => 'applications/auth/controller/login',
     'PhabricatorLogoutController' => 'applications/auth/controller/logout',
     'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
     'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/test',
     'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
     'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
     'PhabricatorMetaMTADaemon' => 'applications/metamta/daemon/mta',
     'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list',
     'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail',
     'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/mail/__tests__',
     'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist',
     'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit',
     'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists',
     'PhabricatorMetaMTAReceiveController' => 'applications/metamta/controller/receive',
     'PhabricatorMetaMTAReceivedListController' => 'applications/metamta/controller/receivedlist',
     'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/receivedmail',
     'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send',
     'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view',
     'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/default',
     'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/oauthdiagnostics',
     'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure',
     'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth',
     'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base',
     'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook',
     'PhabricatorOAuthProviderGithub' => 'applications/auth/oauth/provider/github',
     'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base',
     'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink',
     'PhabricatorObjectHandle' => 'applications/phid/handle',
     'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
     'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
     'PhabricatorOwnersController' => 'applications/owners/controller/base',
     'PhabricatorOwnersDAO' => 'applications/owners/storage/base',
     'PhabricatorOwnersDeleteController' => 'applications/owners/controller/delete',
     'PhabricatorOwnersDetailController' => 'applications/owners/controller/detail',
     'PhabricatorOwnersEditController' => 'applications/owners/controller/edit',
     'PhabricatorOwnersListController' => 'applications/owners/controller/list',
     'PhabricatorOwnersOwner' => 'applications/owners/storage/owner',
     'PhabricatorOwnersPackage' => 'applications/owners/storage/package',
     'PhabricatorOwnersPath' => 'applications/owners/storage/path',
     'PhabricatorPHID' => 'applications/phid/storage/phid',
     'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate',
     'PhabricatorPHIDConstants' => 'applications/phid/constants',
     'PhabricatorPHIDController' => 'applications/phid/controller/base',
     'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
     'PhabricatorPHIDListController' => 'applications/phid/controller/list',
     'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup',
     'PhabricatorPeopleController' => 'applications/people/controller/base',
     'PhabricatorPeopleEditController' => 'applications/people/controller/edit',
     'PhabricatorPeopleListController' => 'applications/people/controller/list',
     'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
     'PhabricatorPeopleProfileEditController' => 'applications/people/controller/profileedit',
     'PhabricatorPreferencesController' => 'applications/preferences/controller/base',
     'PhabricatorProject' => 'applications/project/storage/project',
     'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
     'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
     'PhabricatorProjectController' => 'applications/project/controller/base',
     'PhabricatorProjectDAO' => 'applications/project/storage/base',
     'PhabricatorProjectEditController' => 'applications/project/controller/edit',
     'PhabricatorProjectListController' => 'applications/project/controller/list',
     'PhabricatorProjectProfile' => 'applications/project/storage/profile',
     'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
     'PhabricatorRedirectController' => 'applications/base/controller/redirect',
     'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
     'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion',
     'PhabricatorRemarkupRuleImageMacro' => 'infrastructure/markup/remarkup/markuprule/imagemacro',
     'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest',
     'PhabricatorRemarkupRuleProxyImage' => 'infrastructure/markup/remarkup/markuprule/proxyimage',
     'PhabricatorRepository' => 'applications/repository/storage/repository',
     'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/arcanistproject',
     'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/arcansistprojectedit',
     'PhabricatorRepositoryCommit' => 'applications/repository/storage/commit',
     'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/base',
     'PhabricatorRepositoryCommitData' => 'applications/repository/storage/commitdata',
     'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base',
     'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/herald',
     'PhabricatorRepositoryCommitMessageDetailParser' => 'applications/repository/parser/base',
     'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/base',
     'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/base',
     'PhabricatorRepositoryCommitTaskDaemon' => 'applications/repository/daemon/committask',
     'PhabricatorRepositoryController' => 'applications/repository/controller/base',
     'PhabricatorRepositoryCreateController' => 'applications/repository/controller/create',
     'PhabricatorRepositoryDAO' => 'applications/repository/storage/base',
     'PhabricatorRepositoryDaemon' => 'applications/repository/daemon/base',
     'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'applications/repository/parser/default',
     'PhabricatorRepositoryDeleteController' => 'applications/repository/controller/delete',
     'PhabricatorRepositoryEditController' => 'applications/repository/controller/edit',
     'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/git',
     'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git',
     'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/git',
     'PhabricatorRepositoryGitFetchDaemon' => 'applications/repository/daemon/gitfetch',
     'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification',
     'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive',
     'PhabricatorRepositoryListController' => 'applications/repository/controller/list',
     'PhabricatorRepositoryShortcut' => 'applications/repository/storage/shortcut',
     'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/svn',
     'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/svn',
     'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/svn',
     'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype',
+    'PhabricatorSQLPatchList' => 'infrastructure/setup/sql',
     'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument',
     'PhabricatorSearchBaseController' => 'applications/search/controller/base',
     'PhabricatorSearchController' => 'applications/search/controller/search',
     'PhabricatorSearchDAO' => 'applications/search/storage/base',
     'PhabricatorSearchDifferentialIndexer' => 'applications/search/index/indexer/differential',
     'PhabricatorSearchDocument' => 'applications/search/storage/document/document',
     'PhabricatorSearchDocumentField' => 'applications/search/storage/document/field',
     'PhabricatorSearchDocumentIndexer' => 'applications/search/index/indexer/base',
     'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/relationship',
     'PhabricatorSearchExecutor' => 'applications/search/execute/base',
     'PhabricatorSearchField' => 'applications/search/constants/field',
     'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest',
     'PhabricatorSearchMySQLExecutor' => 'applications/search/execute/mysql',
     'PhabricatorSearchQuery' => 'applications/search/storage/query',
     'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
+    'PhabricatorSetup' => 'infrastructure/setup',
     'PhabricatorStandardPageView' => 'view/page/standard',
     'PhabricatorStatusController' => 'applications/status/base',
     'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/taskmaster',
     'PhabricatorTestCase' => 'infrastructure/testing/testcase',
     'PhabricatorTimelineCursor' => 'infrastructure/daemon/timeline/storage/cursor',
     'PhabricatorTimelineDAO' => 'infrastructure/daemon/timeline/storage/base',
     'PhabricatorTimelineEvent' => 'infrastructure/daemon/timeline/storage/event',
     'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/eventdata',
     'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator',
     'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
     'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
     'PhabricatorUIExample' => 'applications/uiexample/examples/base',
     'PhabricatorUIExampleController' => 'applications/uiexample/controller/base',
     'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/render',
     'PhabricatorUIListFilterExample' => 'applications/uiexample/examples/listfilter',
     'PhabricatorUIPagerExample' => 'applications/uiexample/examples/pager',
     'PhabricatorUser' => 'applications/people/storage/user',
     'PhabricatorUserDAO' => 'applications/people/storage/base',
     'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
     'PhabricatorUserPreferences' => 'applications/people/storage/preferences',
     'PhabricatorUserProfile' => 'applications/people/storage/profile',
     'PhabricatorUserSettingsController' => 'applications/people/controller/settings',
     'PhabricatorWorker' => 'infrastructure/daemon/workers/worker',
     'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/base',
     'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/task',
     'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/taskdata',
     'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/workertaskdetail',
     'PhabricatorXHPASTViewController' => 'applications/xhpastview/controller/base',
     'PhabricatorXHPASTViewDAO' => 'applications/xhpastview/storage/base',
     'PhabricatorXHPASTViewFrameController' => 'applications/xhpastview/controller/viewframe',
     'PhabricatorXHPASTViewFramesetController' => 'applications/xhpastview/controller/viewframeset',
     'PhabricatorXHPASTViewInputController' => 'applications/xhpastview/controller/viewinput',
     'PhabricatorXHPASTViewPanelController' => 'applications/xhpastview/controller/viewpanel',
     'PhabricatorXHPASTViewParseTree' => 'applications/xhpastview/storage/parsetree',
     'PhabricatorXHPASTViewRunController' => 'applications/xhpastview/controller/run',
     'PhabricatorXHPASTViewStreamController' => 'applications/xhpastview/controller/viewstream',
     'PhabricatorXHPASTViewTreeController' => 'applications/xhpastview/controller/viewtree',
     'PhabricatorXHProfController' => 'applications/xhprof/controller/base',
     'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile',
     'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol',
     'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel',
   ),
   'function' =>
   array(
     '_qsprintf_check_scalar_type' => 'storage/qsprintf',
     '_qsprintf_check_type' => 'storage/qsprintf',
     'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
     'celerity_register_resource_map' => 'infrastructure/celerity/map',
     'javelin_render_tag' => 'infrastructure/javelin/markup',
     'phabricator_format_relative_time' => 'view/utils',
     'phabricator_format_timestamp' => 'view/utils',
     'phabricator_format_units_generic' => 'view/utils',
     'phabricator_render_form' => 'infrastructure/javelin/markup',
     'qsprintf' => 'storage/qsprintf',
     'queryfx' => 'storage/queryfx',
     'queryfx_all' => 'storage/queryfx',
     'queryfx_one' => 'storage/queryfx',
     'require_celerity_resource' => 'infrastructure/celerity/api',
     'vqsprintf' => 'storage/qsprintf',
     'vqueryfx' => 'storage/queryfx',
     'vqueryfx_all' => 'storage/queryfx',
     'xsprintf_query' => 'storage/qsprintf',
   ),
   'requires_class' =>
   array(
     'Aphront304Response' => 'AphrontResponse',
     'Aphront400Response' => 'AphrontResponse',
     'Aphront404Response' => 'AphrontResponse',
     'AphrontAjaxResponse' => 'AphrontResponse',
     'AphrontCrumbsView' => 'AphrontView',
     'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
     'AphrontDefaultApplicationController' => 'AphrontController',
     'AphrontDialogResponse' => 'AphrontResponse',
     'AphrontDialogView' => 'AphrontView',
     'AphrontErrorView' => 'AphrontView',
     'AphrontFileResponse' => 'AphrontResponse',
     'AphrontFormCheckboxControl' => 'AphrontFormControl',
     'AphrontFormControl' => 'AphrontView',
     'AphrontFormDividerControl' => 'AphrontFormControl',
     'AphrontFormFileControl' => 'AphrontFormControl',
     'AphrontFormMarkupControl' => 'AphrontFormControl',
     'AphrontFormPasswordControl' => 'AphrontFormControl',
     'AphrontFormRecaptchaControl' => 'AphrontFormControl',
     'AphrontFormSelectControl' => 'AphrontFormControl',
     'AphrontFormStaticControl' => 'AphrontFormControl',
     'AphrontFormSubmitControl' => 'AphrontFormControl',
     'AphrontFormTextAreaControl' => 'AphrontFormControl',
     'AphrontFormTextControl' => 'AphrontFormControl',
     'AphrontFormToggleButtonsControl' => 'AphrontFormControl',
     'AphrontFormTokenizerControl' => 'AphrontFormControl',
     'AphrontFormView' => 'AphrontView',
     'AphrontHeadsupActionListView' => 'AphrontView',
     'AphrontHeadsupActionView' => 'AphrontView',
     'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection',
     'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase',
     'AphrontListFilterView' => 'AphrontView',
     'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
     'AphrontNullView' => 'AphrontView',
     'AphrontPageView' => 'AphrontView',
     'AphrontPagerView' => 'AphrontView',
     'AphrontPanelView' => 'AphrontView',
     'AphrontQueryAccessDeniedException' => 'AphrontQueryRecoverableException',
     'AphrontQueryConnectionException' => 'AphrontQueryException',
     'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
     'AphrontQueryCountException' => 'AphrontQueryException',
     'AphrontQueryDuplicateKeyException' => 'AphrontQueryException',
     'AphrontQueryObjectMissingException' => 'AphrontQueryException',
     'AphrontQueryParameterException' => 'AphrontQueryException',
     'AphrontQueryRecoverableException' => 'AphrontQueryException',
     'AphrontRedirectException' => 'AphrontException',
     'AphrontRedirectResponse' => 'AphrontResponse',
     'AphrontRequestFailureView' => 'AphrontView',
     'AphrontSideNavView' => 'AphrontView',
     'AphrontTableView' => 'AphrontView',
     'AphrontTokenizerTemplateView' => 'AphrontView',
     'AphrontTypeaheadTemplateView' => 'AphrontView',
     'AphrontWebpageResponse' => 'AphrontResponse',
     'CelerityResourceController' => 'AphrontController',
     'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
     'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod',
     'ConduitAPI_daemon_launched_Method' => 'ConduitAPIMethod',
     'ConduitAPI_daemon_log_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getalldiffs_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getdiff_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getrevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getrevisionfeedback_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'ConduitAPIMethod',
     'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
     'ConduitAPI_path_getowners_Method' => 'ConduitAPIMethod',
     'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
     'ConduitAPI_user_whoami_Method' => 'ConduitAPIMethod',
     'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
     'DarkConsoleController' => 'PhabricatorController',
     'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
     'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
     'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
     'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin',
     'DifferentialAddCommentView' => 'AphrontView',
     'DifferentialAttachController' => 'DifferentialController',
     'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
     'DifferentialChangeset' => 'DifferentialDAO',
     'DifferentialChangesetDetailView' => 'AphrontView',
     'DifferentialChangesetListView' => 'AphrontView',
     'DifferentialChangesetViewController' => 'DifferentialController',
     'DifferentialComment' => 'DifferentialDAO',
     'DifferentialCommentMail' => 'DifferentialMail',
     'DifferentialCommentPreviewController' => 'DifferentialController',
     'DifferentialCommentSaveController' => 'DifferentialController',
     'DifferentialController' => 'PhabricatorController',
     'DifferentialDAO' => 'PhabricatorLiskDAO',
     'DifferentialDiff' => 'DifferentialDAO',
     'DifferentialDiffContentMail' => 'DifferentialMail',
     'DifferentialDiffCreateController' => 'DifferentialController',
     'DifferentialDiffProperty' => 'DifferentialDAO',
     'DifferentialDiffTableOfContentsView' => 'AphrontView',
     'DifferentialDiffViewController' => 'DifferentialController',
     'DifferentialExceptionMail' => 'DifferentialMail',
     'DifferentialHunk' => 'DifferentialDAO',
     'DifferentialInlineComment' => 'DifferentialDAO',
     'DifferentialInlineCommentEditController' => 'DifferentialController',
     'DifferentialInlineCommentPreviewController' => 'DifferentialController',
     'DifferentialInlineCommentView' => 'AphrontView',
     'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
     'DifferentialReviewRequestMail' => 'DifferentialMail',
     'DifferentialRevision' => 'DifferentialDAO',
     'DifferentialRevisionCommentListView' => 'AphrontView',
     'DifferentialRevisionCommentView' => 'AphrontView',
     'DifferentialRevisionDetailView' => 'AphrontView',
     'DifferentialRevisionEditController' => 'DifferentialController',
     'DifferentialRevisionListController' => 'DifferentialController',
     'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
     'DifferentialRevisionViewController' => 'DifferentialController',
     'DifferentialSubscribeController' => 'DifferentialController',
     'DifferentialViewTime' => 'DifferentialDAO',
     'DiffusionBranchTableView' => 'DiffusionView',
     'DiffusionBrowseController' => 'DiffusionController',
     'DiffusionBrowseFileController' => 'DiffusionController',
     'DiffusionBrowseTableView' => 'DiffusionView',
     'DiffusionChangeController' => 'DiffusionController',
     'DiffusionCommitChangeTableView' => 'DiffusionView',
     'DiffusionCommitController' => 'DiffusionController',
     'DiffusionController' => 'PhabricatorController',
     'DiffusionDiffController' => 'DiffusionController',
     'DiffusionGitBranchQuery' => 'DiffusionBranchQuery',
     'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionGitDiffQuery' => 'DiffusionDiffQuery',
     'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
     'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionGitLastModifiedQuery' => 'DiffusionLastModifiedQuery',
     'DiffusionGitRequest' => 'DiffusionRequest',
     'DiffusionHistoryController' => 'DiffusionController',
     'DiffusionHistoryTableView' => 'DiffusionView',
     'DiffusionHomeController' => 'DiffusionController',
     'DiffusionLastModifiedController' => 'DiffusionController',
     'DiffusionPathCompleteController' => 'DiffusionController',
     'DiffusionPathValidateController' => 'DiffusionController',
     'DiffusionRepositoryController' => 'DiffusionController',
     'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionSvnDiffQuery' => 'DiffusionDiffQuery',
     'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery',
     'DiffusionSvnHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionSvnLastModifiedQuery' => 'DiffusionLastModifiedQuery',
     'DiffusionSvnRequest' => 'DiffusionRequest',
     'DiffusionView' => 'AphrontView',
     'HeraldAction' => 'HeraldDAO',
     'HeraldApplyTranscript' => 'HeraldDAO',
     'HeraldCommitAdapter' => 'HeraldObjectAdapter',
     'HeraldCondition' => 'HeraldDAO',
     'HeraldController' => 'PhabricatorController',
     'HeraldDAO' => 'PhabricatorLiskDAO',
     'HeraldDeleteController' => 'HeraldController',
     'HeraldDifferentialRevisionAdapter' => 'HeraldObjectAdapter',
     'HeraldDryRunAdapter' => 'HeraldObjectAdapter',
     'HeraldHomeController' => 'HeraldController',
     'HeraldNewController' => 'HeraldController',
     'HeraldRule' => 'HeraldDAO',
     'HeraldRuleController' => 'HeraldController',
     'HeraldTestConsoleController' => 'HeraldController',
     'HeraldTranscript' => 'HeraldDAO',
     'HeraldTranscriptController' => 'HeraldController',
     'HeraldTranscriptListController' => 'HeraldController',
     'LiskIsolationTestCase' => 'PhabricatorTestCase',
     'LiskIsolationTestDAO' => 'LiskDAO',
     'ManiphestController' => 'PhabricatorController',
     'ManiphestDAO' => 'PhabricatorLiskDAO',
     'ManiphestTask' => 'ManiphestDAO',
     'ManiphestTaskDetailController' => 'ManiphestController',
     'ManiphestTaskEditController' => 'ManiphestController',
     'ManiphestTaskListController' => 'ManiphestController',
     'ManiphestTaskListView' => 'AphrontView',
     'ManiphestTaskSelectorSearchController' => 'ManiphestController',
     'ManiphestTaskSummaryView' => 'AphrontView',
     'ManiphestTransaction' => 'ManiphestDAO',
     'ManiphestTransactionDetailView' => 'AphrontView',
     'ManiphestTransactionListView' => 'AphrontView',
     'ManiphestTransactionPreviewController' => 'ManiphestController',
     'ManiphestTransactionSaveController' => 'ManiphestController',
     'Phabricator404Controller' => 'PhabricatorController',
     'PhabricatorAuthController' => 'PhabricatorController',
     'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
     'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
     'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
     'PhabricatorConduitController' => 'PhabricatorController',
     'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
     'PhabricatorConduitLogController' => 'PhabricatorConduitController',
     'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
     'PhabricatorController' => 'AphrontController',
     'PhabricatorDaemon' => 'PhutilDaemon',
     'PhabricatorDaemonCombinedLogController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonController' => 'PhabricatorController',
     'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO',
     'PhabricatorDaemonLog' => 'PhabricatorDaemonDAO',
     'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO',
     'PhabricatorDaemonLogEventsView' => 'AphrontView',
     'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonLogListView' => 'AphrontView',
     'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonTimelineConsoleController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonTimelineEventController' => 'PhabricatorDaemonController',
     'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryController' => 'PhabricatorController',
     'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
     'PhabricatorDraft' => 'PhabricatorDraftDAO',
     'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
     'PhabricatorEditPreferencesController' => 'PhabricatorPreferencesController',
     'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
     'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
     'PhabricatorFile' => 'PhabricatorFileDAO',
     'PhabricatorFileController' => 'PhabricatorController',
     'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFileImageMacro' => 'PhabricatorFileDAO',
     'PhabricatorFileListController' => 'PhabricatorFileController',
     'PhabricatorFileMacroDeleteController' => 'PhabricatorFileController',
     'PhabricatorFileMacroEditController' => 'PhabricatorFileController',
     'PhabricatorFileMacroListController' => 'PhabricatorFileController',
     'PhabricatorFileProxyController' => 'PhabricatorFileController',
     'PhabricatorFileProxyImage' => 'PhabricatorFileDAO',
     'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
     'PhabricatorFileUploadController' => 'PhabricatorFileController',
     'PhabricatorFileViewController' => 'PhabricatorFileController',
     'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker',
     'PhabricatorJavelinLinter' => 'ArcanistLinter',
     'PhabricatorLintEngine' => 'PhutilLintEngine',
     'PhabricatorLiskDAO' => 'LiskDAO',
     'PhabricatorLoginController' => 'PhabricatorAuthController',
     'PhabricatorLogoutController' => 'PhabricatorAuthController',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMetaMTAController' => 'PhabricatorController',
     'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
     'PhabricatorMetaMTADaemon' => 'PhabricatorDaemon',
     'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase',
     'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAReceiveController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAReceivedListController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController',
     'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController',
     'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController',
     'PhabricatorOAuthFailureView' => 'AphrontView',
     'PhabricatorOAuthLoginController' => 'PhabricatorAuthController',
     'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthProviderGithub' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController',
     'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
     'PhabricatorOwnersController' => 'PhabricatorController',
     'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
     'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
     'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO',
     'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO',
     'PhabricatorPHID' => 'PhabricatorPHIDDAO',
     'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDController' => 'PhabricatorController',
     'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
     'PhabricatorPHIDListController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
     'PhabricatorPeopleController' => 'PhabricatorController',
     'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController',
     'PhabricatorPreferencesController' => 'PhabricatorController',
     'PhabricatorProject' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectController' => 'PhabricatorController',
     'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
     'PhabricatorProjectEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectListController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
     'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
     'PhabricatorRedirectController' => 'PhabricatorController',
     'PhabricatorRemarkupRuleDifferential' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleManiphest' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleProxyImage' => 'PhutilRemarkupRule',
     'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker',
     'PhabricatorRepositoryCommitTaskDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryController' => 'PhabricatorController',
     'PhabricatorRepositoryCreateController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon',
     'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'PhabricatorRepositoryCommitMessageDetailParser',
     'PhabricatorRepositoryDeleteController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryEditController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
     'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
     'PhabricatorRepositoryGitFetchDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
     'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
     'PhabricatorSearchBaseController' => 'PhabricatorController',
     'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
     'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO',
     'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor',
     'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
     'PhabricatorStandardPageView' => 'AphrontPageView',
     'PhabricatorStatusController' => 'PhabricatorController',
     'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon',
     'PhabricatorTestCase' => 'ArcanistPhutilTestCase',
     'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
     'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
     'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
     'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
     'PhabricatorUIExampleController' => 'PhabricatorController',
     'PhabricatorUIExampleRenderController' => 'PhabricatorUIExampleController',
     'PhabricatorUIListFilterExample' => 'PhabricatorUIExample',
     'PhabricatorUIPagerExample' => 'PhabricatorUIExample',
     'PhabricatorUser' => 'PhabricatorUserDAO',
     'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
     'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
     'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
     'PhabricatorUserProfile' => 'PhabricatorUserDAO',
     'PhabricatorUserSettingsController' => 'PhabricatorPeopleController',
     'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO',
     'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO',
     'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO',
     'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController',
     'PhabricatorXHPASTViewController' => 'PhabricatorController',
     'PhabricatorXHPASTViewDAO' => 'PhabricatorLiskDAO',
     'PhabricatorXHPASTViewFrameController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewFramesetController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewInputController' => 'PhabricatorXHPASTViewPanelController',
     'PhabricatorXHPASTViewPanelController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewParseTree' => 'PhabricatorXHPASTViewDAO',
     'PhabricatorXHPASTViewRunController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewStreamController' => 'PhabricatorXHPASTViewPanelController',
     'PhabricatorXHPASTViewTreeController' => 'PhabricatorXHPASTViewPanelController',
     'PhabricatorXHProfController' => 'PhabricatorController',
     'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController',
     'PhabricatorXHProfProfileSymbolView' => 'AphrontView',
     'PhabricatorXHProfProfileTopLevelView' => 'AphrontView',
   ),
   'requires_interface' =>
   array(
   ),
 ));
diff --git a/src/docs/configuration_guide.diviner b/src/docs/configuration_guide.diviner
index fd247d159a..e072bbed5b 100644
--- a/src/docs/configuration_guide.diviner
+++ b/src/docs/configuration_guide.diviner
@@ -1,123 +1,127 @@
 @title Configuration Guide
 @group config
 
 This document contains basic configuration instructions for Phabricator.
 
 = Prerequisites =
 
 This document assumes you've already installed all the components you need.
 If you haven't, see @{article:Installation Guide}.
 
 = Configuring MySQL =
 
 Get MySQL running and verify you can connect to it. Consult the MySQL
 documentation for help. When MySQL works, you need to load the Phabricator
 schemata into it. First, load the initial database schema.
 
   mysql -uroot < path/to/phabricator/resources/sql/init/initialize.sql
 
-After this you need to upgrade the schema see @{article:Upgrading Schema},
+After this you need to upgrade the schema (see @{article:Upgrading Schema}),
 but you need to finish the rest of the configuration first.
 
+= Configuring Phabricator =
+
+Create a new file here:
+
+  path/to/phabricator/conf/custom/myconfig.conf.php
+
+...where ##myconfig## is some name which identifies your installation. Put this
+in the file:
+
+  <?php
+
+  return array(
+
+    // Important! This will put Phabricator into setup mode to help you
+    // configure things.
+    'phabricator.setup' => true,
+
+  ) + phabricator_read_config_file('production');
+
+For the last line, you can also use ##'development'## instead of
+##'production'## if you are planning to develop Phabricator itself. This will
+turn on some debugging features.
+
 = Configuring Apache =
 
 Get Apache running and verify it's serving a test page. Consult the Apache
 documentation for help. Make sure ##mod_php## and ##mod_rewrite## are enabled,
 and ##mod_ssl## if you intend to set up SSL.
 
 If you haven't already, set up a domain name to point to the host you're
 installing on. You can either install Phabricator on a subdomain (like
 phabricator.example.com) or an entire domain, but you can not install it in
 some subdirectory of an existing website. Navigate to whatever domain you're
 going to use and make sure Apache serves you something to verify that DNS
 is correctly configured.
 
 Now, either create a VirtualHost entry (to put Phabricator on a subdomain)
 or edit the Directory entry for the DocumentRoot. It should look something like
 this:
 
   <VirtualHost *>
     # Change this to the domain which points to your host.
     ServerName phabricator.example.com
 
     # Change this to the path where you put 'phabricator' when you checked it
     # out from github when following the Installation Guide.
     DocumentRoot /path/to/phabricator/webroot
 
     RewriteEngine on
     RewriteRule ^/rsrc/(.*)     -                       [L,QSA]
     RewriteRule ^/favicon.ico   -                       [L,QSA]
     RewriteRule ^(.*)$          /index.php?__path__=$1  [L,QSA]
 
-    # This will use "setup" defaults for configuration options, which will
-    # expose error messages. Before you make the install public, you should
-    # change this to "production" and/or customize your configuration. See
-    # the next section for details.
-    SetEnv PHABRICATOR_ENV setup
+    # This will use the config file you set up in the previous step. If you
+    # called it something other than 'myconfig', put that here.
+    SetEnv PHABRICATOR_ENV custom/myconfig
   </VirtualHost>
 
 Now, restart apache and navigate to whichever subdomain you set up. You should
-either see the Phabricator login screen, which means you're all set, or some
-useful error message telling you what else you need to fix (for instance, you
-may need to set up MySQL credentials). If you see something else, you did
-something very wrong and/or this document lied to you.
+either see the Phabricator setup screen, which is a simple text page that looks
+something like this:
+
+  PHABRICATOR SETUP
+
+  This setup mode will guide you through setting up your Phabricator
+  configuration.
+
+  >>>  REQUIRED PHP EXTENSIONS  ------------------------------------------------
+  ...
+
+If you see this, you're in good shape. Follow the instructions and correct any
+problems setup detects. If you don't see it but you do see a useful error
+message, try to fix that. If neither of these cover you, something is wrong.
+If you can't figure it out, come get help in IRC or on the mailing list (see
+http://phabricator.org/ for links).
 
 = Configuring Phabricator =
 
-Now that basic setup is complete, you should configure Phabricator. Phabricator
-configuration options which control how the applications behave are stored here:
+Now that basic setup is complete, you should configure Phabricator for your
+installation. Phabricator configuration options which control how the
+applications behave are documented here:
 
-  /path/to/phabricator/conf/
+  /path/to/phabricator/conf/default.conf.php
 
-There are several configuration templates:
+There are several builtin configurations:
 
   - ##default.conf.php##: root configuration, lists every configuration option
     and sets some default for it. Look in this file to figure out what you can
     configure.
   - ##development.conf.php##: pulls in ##default.conf.php##, but overrides some
     configuration options to better values for doing development on Phabricator.
     You probably don't need to even look at this file unless you're making
     changes to Phabricator itself.
   - ##production.conf.php##: pulls in ##default.conf.php##, but overrides some
     configuration options to provide better values for a production install.
-    Once you've completed setup, you should switch to this configuration or
-    one based upon it.
-  - ##setup.conf.php##: pulls in ##default.conf.php##, but sets some flags that
-    make it easier to set up a Phabricator install. Switch away from this before
-    deploying a production install.
-
-While you can use these templates as-is, you'll probably want to set up custom
-configuration. To do this, create a new file:
-
-  /path/to/phabricator/conf/custom/myconfig.conf.php
-
-Put this in the file:
-
-  <?php
-
-  return array(
-
-    // This is just an example.
-    'some.config' => 'some_value',
-
-  ) + phabricator_read_config_file('production');
-
-This will create a new config called "custom/myconfig" which uses the
-"production" config as the default but allows you to override options. You can
-select it by editing the VirtualHost or Directory entry you set up when
-configuring Apache:
-
-  <VirtualHost *>
-    # ...
-    SetEnv PHABRICATOR_ENV custom/myconfig
-    # ...
-  </VirtualHost>
 
-Now, look through ##default.conf.php## and override any options you want to
-change by providing overrides in ##myconfig.conf.php##.
+To actually configure your install, edit your ##custom/myconfig.conf.php## file
+and override values from either the ##'production'## or ##'development'##
+configurations. You should not edit the builtin configurations directly because
+that will make upgrading Phabricator more difficult in the future.
 
 = Upgrading Schema =
 
 After you have configured Phabricator, you need to upgrade the database
-schema, see @{article:Upgrading Schema}. You'll also need to do this after you
+schema -- see @{article:Upgrading Schema}. You'll also need to do this after you
 update the code in the future.
diff --git a/src/infrastructure/setup/PhabricatorSetup.php b/src/infrastructure/setup/PhabricatorSetup.php
new file mode 100644
index 0000000000..842c84eee3
--- /dev/null
+++ b/src/infrastructure/setup/PhabricatorSetup.php
@@ -0,0 +1,298 @@
+<?php
+
+/*
+ * Copyright 2011 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.
+ */
+
+class PhabricatorSetup {
+
+  const EXPECTED_SCHEMA_VERSION = 36;
+
+  public static function runSetup() {
+    header("Content-Type: text/plain");
+    self::write("PHABRICATOR SETUP\n\n");
+
+    // Force browser to stop buffering.
+    self::write(str_repeat(' ', 2048));
+    usleep(250000);
+
+    self::write("This setup mode will guide you through setting up your ".
+                "Phabricator configuration.\n");
+
+    self::writeHeader("REQUIRED PHP EXTENSIONS");
+    $extensions = array(
+      'mysql',
+      'hash',
+      'json',
+    );
+    foreach ($extensions as $extension) {
+      $ok = self::requireExtension($extension);
+      if (!$ok) {
+        self::writeFailure();
+        self::write("Setup failure! Install PHP extension '{$extension}'.");
+        return;
+      }
+    }
+    self::write("[OKAY] All extensions OKAY\n\n");
+
+    self::writeHeader("GIT SUBMODULES");
+    $root = dirname(phutil_get_library_root('phabricator'));
+    if (!Filesystem::pathExists($root.'/.git')) {
+      self::write(" skip  Not a git clone.\n\n");
+    } else {
+      list($info) = execx(
+        '(cd %s && git submodule status)',
+        $root);
+      foreach (explode("\n", rtrim($info)) as $line) {
+        $matches = null;
+        if (!preg_match('/^(.)([0-9a-f]{40}) (\S+)(?: |$)/', $line, $matches)) {
+          self::writeFailure();
+          self::write(
+            "Setup failure! 'git submodule' produced unexpected output:\n".
+            $line);
+          return;
+        }
+
+        $status = $matches[1];
+        $module = $matches[3];
+
+        switch ($status) {
+          case '-':
+          case '+':
+          case 'U':
+            self::writeFailure();
+            self::write(
+              "Setup failure! Git submodule '{$module}' is not up to date. ".
+              "Run:\n\n".
+              "  cd {$root} && git submodule update --init\n\n".
+              "...to update submodules.");
+            return;
+          case ' ':
+            self::write(" okay  Git submodule '{$module}' up to date.\n");
+            break;
+          default:
+            self::writeFailure();
+            self::write(
+              "Setup failure! 'git submodule' reported unknown status ".
+              "'{$status}' for submodule '{$module}'. This is a bug; report ".
+              "it to the Phabricator maintainers.");
+            return;
+        }
+      }
+    }
+    self::write("[OKAY] All submodules OKAY.");
+
+    self::writeHeader("BASIC CONFIGURATION");
+
+    $env = PhabricatorEnv::getEnvConfig('phabricator.env');
+    if ($env == 'production' || $env == 'default' || $env == 'development') {
+      self::writeFailure();
+      self::write(
+        "Setup failure! Your PHABRICATOR_ENV is set to '{$env}', which is ".
+        "a Phabricator environmental default. You should create a custom ".
+        "environmental configuration instead of editing the defaults ".
+        "directly. See this document for instructions:\n");
+        self::writeDoc('article/Configuration_Guide.html');
+      return;
+    } else {
+      self::write(" okay  Custom configuration loaded.\n");
+    }
+
+    if (!PhabricatorEnv::getEnvConfig('phabricator.base-uri')) {
+      self::writeFailure();
+      self::write(
+        "Setup failure! You must specify 'phabricator.base-uri' in your ".
+        "custom config file. Refer to 'default.conf.php' for documentation ".
+        "on configuration options.\n");
+      return;
+    } else {
+      self::write(" okay  phabricator.base-uri\n");
+    }
+
+    self::write("[OKAY] Basic configuration OKAY\n");
+
+    self::writeHeader('FACEBOOK INTEGRATION');
+    $fb_auth = PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
+    if (!$fb_auth) {
+      self::write(" skip  'facebook.auth-enabled' not enabled.\n");
+    } else {
+      self::write(" okay  'facebook.auth-enabled' is enabled.\n");
+      $app_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
+      $app_secret = PhabricatorEnv::getEnvConfig('facebook.application-secret');
+
+      if (!$app_id) {
+        self::writeFailure();
+        self::write(
+          "Setup failure! 'facebook.auth-enabled' is true but there is no ".
+          "setting for 'facebook.application-id'.\n");
+        return;
+      } else {
+        self::write(" okay  'facebook.application-id' is set.\n");
+      }
+
+      if (!is_string($app_id)) {
+        self::writeFailure();
+        self::write(
+          "Setup failure! 'facebook.application-id' should be a string.");
+        return;
+      } else {
+        self::write(" okay  'facebook.application-id' is string.\n");
+      }
+
+      if (!$app_secret) {
+        self::writeFailure();
+        self::write(
+          "Setup failure! 'facebook.auth-enabled' is true but there is no ".
+          "setting for 'facebook.application-secret'.");
+        return;
+      } else {
+        self::write(" okay  'facebook.application-secret is set.\n");
+      }
+
+      self::write("[OKAY] Facebook integration OKAY\n");
+    }
+
+    self::writeHeader("MySQL DATABASE CONFIGURATION");
+
+    $conn_user = PhabricatorEnv::getEnvConfig('mysql.user');
+    $conn_pass = PhabricatorEnv::getEnvConfig('mysql.pass');
+    $conn_host = PhabricatorEnv::getEnvConfig('mysql.host');
+
+    $timeout = ini_get('mysql.connect_timeout');
+    if ($timeout > 5) {
+      self::writeNote(
+        "Your MySQL connect timeout is very high ({$timeout} seconds). ".
+        "Consider reducing it by setting 'mysql.connect_timeout' in your ".
+        "php.ini.");
+    }
+
+    self::write(" okay  Trying to connect to MySQL database ".
+                "{$conn_user}@{$conn_host}...\n");
+
+    ini_set('mysql.connect_timeout', 2);
+
+    $conn_raw = new AphrontMySQLDatabaseConnection(
+      array(
+        'user'      => $conn_user,
+        'pass'      => $conn_pass,
+        'host'      => $conn_host,
+        'database'  => null,
+      ));
+
+    try {
+      queryfx($conn_raw, 'SELECT 1');
+      self::write(" okay  Connection successful!\n");
+    } catch (AphrontQueryConnectionException $ex) {
+      self::writeFailure();
+      self::write(
+        "Setup failure! Unable to connect to MySQL database ".
+        "'{$conn_host}' with user '{$conn_user}'. Edit Phabricator ".
+        "configuration keys 'mysql.user', 'mysql.host' and 'mysql.pass' to ".
+        "enable Phabricator to connect.");
+      return;
+    }
+
+    $databases = queryfx_all($conn_raw, 'SHOW DATABASES');
+    $databases = ipull($databases, 'Database');
+    $databases = array_fill_keys($databases, true);
+    if (empty($databases['phabricator_meta_data'])) {
+      self::writeFailure();
+      self::write(
+        "Setup failure! You haven't loaded the 'initialize.sql' file into ".
+        "MySQL. This file initializes necessary databases. See this guide for ".
+        "instructions:\n");
+      self::writeDoc('article/Configuration_Guide.html');
+      return;
+    } else {
+      self::write(" okay  Databases have been initialized.\n");
+    }
+
+    $schema_version = queryfx_one(
+      $conn_raw,
+      'SELECT version FROM phabricator_meta_data.schema_version');
+    $schema_version = idx($schema_version, 'version', 'null');
+
+    $expect = PhabricatorSQLPatchList::getExpectedSchemaVersion();
+    if ($schema_version != $expect) {
+      self::writeFailure();
+      self::write(
+        "Setup failure! You haven't upgraded your database schema to the ".
+        "latest version. Expected version is '{$expect}', but your local ".
+        "version is '{$schema_version}'. See this guide for instructions:\n");
+      self::writeDoc('article/Upgrading_Schema.html');
+      return;
+    } else {
+      self::write(" okay  Database schema are up to date (v{$expect}).\n");
+    }
+
+    self::write("[OKAY] Database configuration OKAY\n");
+
+
+    self::writeHeader('SUCCESS!');
+    self::write(
+      "Congratulations! Your setup seems mostly correct, or at least fairly ".
+      "reasonable.\n\n".
+      "*** NEXT STEP ***\n".
+      "Edit your configuration file (conf/{$env}.conf.php) and remove the ".
+      "'phabricator.setup' line to finish installation.");
+
+  }
+
+  public static function requireExtension($extension) {
+    if (extension_loaded($extension)) {
+      self::write(" okay  Extension '{$extension}' installed.\n");
+      return true;
+    } else {
+      self::write("[FAIL] Extension '{$extension}' is NOT INSTALLED!\n");
+      return false;
+    }
+  }
+
+  private static function writeFailure() {
+    self::write("\n\n<<< *** FAILURE! *** >>>\n");
+  }
+
+  private static function write($str) {
+    echo $str;
+    ob_flush();
+    flush();
+
+    // This, uh, makes it look cool. -_-
+    usleep(40000);
+  }
+
+  private static function writeNote($note) {
+    self::write(
+      'Note: '.wordwrap($note, 75, "\n      ", true)."\n\n");
+  }
+
+  public static function writeHeader($header) {
+    $template = '>>>'.str_repeat('-', 77);
+    $template = substr_replace(
+      $template,
+      '  '.$header.'  ',
+      3,
+      strlen($header) + 4);
+    self::write("\n\n{$template}\n\n");
+  }
+
+  public static function writeDoc($doc) {
+    self::write(
+      "\n".
+      '    http://phabricator.com/docs/phabricator/'.$doc.
+      "\n\n");
+  }
+
+}
diff --git a/src/infrastructure/setup/__init__.php b/src/infrastructure/setup/__init__.php
new file mode 100644
index 0000000000..e11efddfe6
--- /dev/null
+++ b/src/infrastructure/setup/__init__.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'infrastructure/env');
+phutil_require_module('phabricator', 'infrastructure/setup/sql');
+phutil_require_module('phabricator', 'storage/connection/mysql');
+phutil_require_module('phabricator', 'storage/queryfx');
+
+phutil_require_module('phutil', 'filesystem');
+phutil_require_module('phutil', 'future/exec');
+phutil_require_module('phutil', 'moduleutils');
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorSetup.php');
diff --git a/src/infrastructure/setup/sql/PhabricatorSQLPatchList.php b/src/infrastructure/setup/sql/PhabricatorSQLPatchList.php
new file mode 100644
index 0000000000..a4fda01f5b
--- /dev/null
+++ b/src/infrastructure/setup/sql/PhabricatorSQLPatchList.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * Copyright 2011 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 PhabricatorSQLPatchList {
+
+  public static function getPatchList() {
+    $root = dirname(phutil_get_library_root('phabricator'));
+
+    // Find the patch files
+    $patches_dir = $root.'/resources/sql/patches/';
+    $finder = id(new FileFinder($patches_dir))
+      ->withSuffix('sql');
+    $results = $finder->find();
+
+    $patches = array();
+    foreach ($results as $path) {
+      $matches = array();
+      if (preg_match('/(\d+)\..*\.sql$/', $path, $matches)) {
+        $patches[] = array(
+          'version' => (int)$matches[1],
+          'path'    => $patches_dir.$path,
+        );
+      } else {
+        throw new Exception("Patch file '{$path}' is not properly named.");
+      }
+    }
+
+    // Files are in some 'random' order returned by the operating system
+    // We need to apply them in proper order
+    $patches = isort($patches, 'version');
+
+    return $patches;
+  }
+
+  public static function getExpectedSchemaVersion() {
+    $patches = self::getPatchList();
+    $versions = ipull($patches, 'version');
+    $max_version = max($versions);
+    return $max_version;
+  }
+
+}
diff --git a/src/infrastructure/setup/sql/__init__.php b/src/infrastructure/setup/sql/__init__.php
new file mode 100644
index 0000000000..248a60848c
--- /dev/null
+++ b/src/infrastructure/setup/sql/__init__.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phutil', 'filesystem/filefinder');
+phutil_require_module('phutil', 'moduleutils');
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorSQLPatchList.php');
diff --git a/webroot/index.php b/webroot/index.php
index 7f22c42f2e..a30dcf4b67 100644
--- a/webroot/index.php
+++ b/webroot/index.php
@@ -1,203 +1,208 @@
 <?php
 
 /*
  * Copyright 2011 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.
  */
 
 
 error_reporting(E_ALL | E_STRICT);
 ini_set('memory_limit', -1);
 
 $env = getenv('PHABRICATOR_ENV'); // Apache
 if (!$env) {
   if (isset($_ENV['PHABRICATOR_ENV'])) {
     $env = $_ENV['PHABRICATOR_ENV'];
   }
 }
 
 if (!$env) {
   phabricator_fatal_config_error(
     "The 'PHABRICATOR_ENV' environmental variable is not defined. Modify ".
     "your httpd.conf to include 'SetEnv PHABRICATOR_ENV <env>', where '<env>' ".
     "is one of 'development', 'production', or a custom environment.");
 }
 
 if (!function_exists('mysql_connect')) {
   phabricator_fatal_config_error(
     "The PHP MySQL extension is not installed. This extension is required.");
 }
 
 if (!isset($_REQUEST['__path__'])) {
   phabricator_fatal_config_error(
     "__path__ is not set. Your rewrite rules are not configured correctly.");
 }
 
 if (get_magic_quotes_gpc()) {
   phabricator_fatal_config_error(
     "Your server is configured with PHP 'magic_quotes_gpc' enabled. This ".
     "feature is 'highly discouraged' by PHP's developers and you must ".
     "disable it to run Phabricator. Consult the PHP manual for instructions.");
 }
 
 require_once dirname(dirname(__FILE__)).'/conf/__init_conf__.php';
 
 try {
   $conf = phabricator_read_config_file($env);
   $conf['phabricator.env'] = $env;
 
   setup_aphront_basics();
 
   phutil_require_module('phabricator', 'infrastructure/env');
   PhabricatorEnv::setEnvConfig($conf);
 
   phutil_require_module('phabricator', 'aphront/console/plugin/xhprof/api');
   DarkConsoleXHProfPluginAPI::hookProfiler();
 
   phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
   set_error_handler(
     array('PhutilErrorHandler', 'handleError'));
   set_exception_handler(
     array('PhutilErrorHandler', 'handleException'));
 } catch (Exception $ex) {
   phabricator_fatal_config_error(
     "[Exception] ".$ex->getMessage());
 }
 
 $tz = PhabricatorEnv::getEnvConfig('phabricator.timezone');
 if ($tz) {
   date_default_timezone_set($tz);
 }
 phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
 phutil_require_module('phutil', 'error');
 
 PhutilErrorHandler::setErrorListener(
   array('DarkConsoleErrorLogPluginAPI', 'handleErrors'));
 
 foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
   phutil_load_library($library);
 }
 
+if (PhabricatorEnv::getEnvConfig('phabricator.setup')) {
+  PhabricatorSetup::runSetup();
+  return;
+}
+
 
 $host = $_SERVER['HTTP_HOST'];
 $path = $_REQUEST['__path__'];
 
 switch ($host) {
   default:
     $config_key = 'aphront.default-application-configuration-class';
     $config_class = PhabricatorEnv::getEnvConfig($config_key);
     PhutilSymbolLoader::loadClass($config_class);
     $application = newv($config_class, array());
     break;
 }
 
 
 $application->setHost($host);
 $application->setPath($path);
 $application->willBuildRequest();
 $request = $application->buildRequest();
 $application->setRequest($request);
 list($controller, $uri_data) = $application->buildController();
 try {
   $response = $controller->willBeginExecution();
   if (!$response) {
     $controller->willProcessRequest($uri_data);
     $response = $controller->processRequest();
   }
 } catch (AphrontRedirectException $ex) {
   $response = id(new AphrontRedirectResponse())
     ->setURI($ex->getURI());
 } catch (Exception $ex) {
   $response = $application->handleException($ex);
 }
 
 $response = $application->willSendResponse($response);
 
 $response->setRequest($request);
 
 $response_string = $response->buildResponseString();
 
 $code = $response->getHTTPResponseCode();
 if ($code != 200) {
   header("HTTP/1.0 {$code}");
 }
 
 $headers = $response->getCacheHeaders();
 $headers = array_merge($headers, $response->getHeaders());
 foreach ($headers as $header) {
   list($header, $value) = $header;
   header("{$header}: {$value}");
 }
 
 
 // TODO: This shouldn't be possible in a production-configured environment.
 if (isset($_REQUEST['__profile__']) &&
     ($_REQUEST['__profile__'] == 'all')) {
   $profile = DarkConsoleXHProfPluginAPI::stopProfiler();
   $profile =
     '<div style="text-align: center; background: #ff00ff; padding: 1em;
                  font-size: 24px; font-weight: bold;">'.
       '<a href="/xhprof/profile/'.$profile.'/">'.
         '&gt;&gt;&gt; View Profile &lt;&lt;&lt;'.
       '</a>'.
     '</div>';
   if (strpos($response_string, '<body>') !== false) {
     $response_string = str_replace(
       '<body>',
       '<body>'.$profile,
       $response_string);
   } else {
     echo $profile;
   }
 }
 
 echo $response_string;
 
 
 /**
  * @group aphront
  */
 function setup_aphront_basics() {
   $aphront_root   = dirname(dirname(__FILE__));
   $libraries_root = dirname($aphront_root);
 
   $root = null;
   if (!empty($_SERVER['PHUTIL_LIBRARY_ROOT'])) {
     $root = $_SERVER['PHUTIL_LIBRARY_ROOT'];
   }
 
   ini_set('include_path', $libraries_root.':'.ini_get('include_path'));
   @include_once $root.'libphutil/src/__phutil_library_init__.php';
   if (!@constant('__LIBPHUTIL__')) {
     echo "ERROR: Unable to load libphutil. Update your PHP 'include_path' to ".
          "include the parent directory of libphutil/.\n";
     exit(1);
   }
 
   // Load Phabricator itself using the absolute path, so we never end up doing
   // anything surprising (loading index.php and libraries from different
   // directories).
   phutil_load_library($aphront_root.'/src');
   phutil_load_library('arcanist/src');
 }
 
 function phabricator_fatal_config_error($msg) {
   header('Content-Type: text/plain', $replace = true, $http_error = 500);
   $error = "CONFIG ERROR: ".$msg."\n";
 
   error_log($error);
   echo $error;
 
   die();
 }