diff --git a/conf/default.conf.php b/conf/default.conf.php
index 00adb3931..ee80b79c3 100644
--- a/conf/default.conf.php
+++ b/conf/default.conf.php
@@ -1,489 +1,508 @@
 <?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',
 
 // -- 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'         => 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. If you want to connect to a different
   // port than the default (which is 3306), specify it in the hostname
   // (e.g., db.example.com:1234).
   '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 "sendmail". This is appropriate
   // if sendmail 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,
 
   // If you're using Sendgrid to send email, provide your access credentials
   // here. This will use the REST API. You can also use Sendgrid as a normal
   // SMTP service.
   'sendgrid.api-user'           => null,
   'sendgrid.api-key'            => null,
 
   // You can configure a reply handler domain so that email sent from Maniphest
   // will have a special "Reply To" address like "T123+82+af19f@example.com"
   // that allows recipients to reply by email and interact with tasks. For
   // instructions on configurating reply handlers, see the article
   // "Configuring Inbound Email" in the Phabricator documentation. By default,
   // this is set to 'null' and Phabricator will use a generic 'noreply@' address
   // or the address of the acting user instead of a special reply handler
   // address (see 'metamta.default-address'). If you set a domain here,
   // Phabricator will begin generating private reply handler addresses. See
   // also 'metamta.maniphest.reply-handler' to further configure behavior.
   // This key should be set to the domain part after the @, like "example.com".
   'metamta.maniphest.reply-handler-domain' => null,
 
   // You can follow the instructions in "Configuring Inbound Email" in the
   // Phabricator documentation and set 'metamta.maniphest.reply-handler-domain'
   // to support updating Maniphest tasks by email. If you want more advanced
   // customization than this provides, you can override the reply handler
   // class with an implementation of your own. This will allow you to do things
   // like have a single public reply handler or change how private reply
   // handlers are generated and validated.
   // This key should be set to a loadable subclass of
   // PhabricatorMailReplyHandler (and possibly of ManiphestReplyHandler).
   'metamta.maniphest.reply-handler' => 'ManiphestReplyHandler',
 
   // Prefix prepended to mail sent by Maniphest. You can change this to
   // distinguish between testing and development installs, for example.
   'metamta.maniphest.subject-prefix' => '[Maniphest]',
 
   // See 'metamta.maniphest.reply-handler-domain'. This does the same thing,
   // but allows email replies via Differential.
   'metamta.differential.reply-handler-domain' => null,
 
   // See 'metamta.maniphest.reply-handler'. This does the same thing, but
   // affects Differential.
   'metamta.differential.reply-handler' => 'DifferentialReplyHandler',
 
   // Prefix prepended to mail sent by Differential.
   'metamta.differential.subject-prefix' => '[Differential]',
 
   // By default, Phabricator generates unique reply-to addresses and sends a
   // separate email to each recipient when you enable reply handling. This is
   // more secure than using "From" to establish user identity, but can mean
   // users may receive multiple emails when they are on mailing lists. Instead,
   // you can use a single, non-unique reply to address and authenticate users
   // based on the "From" address by setting this to 'true'. This trades away
   // a little bit of security for convenience, but it's reasonable in many
   // installs. Object interactions are still protected using hashes in the
   // single public email address, so objects can not be replied to blindly.
   'metamta.public-replies' => false,
 
   // You can configure an email address like "bugs@phabricator.example.com"
   // which will automatically create Maniphest tasks when users send email
   // to it. This relies on the "From" address to authenticate users, so it is
   // is not completely secure. To set this up, enter a complete email
   // address like "bugs@phabricator.example.com" and then configure mail to
   // that address so it routed to Phabricator (if you've already configured
   // reply handlers, you're probably already done). See "Configuring Inbound
   // Email" in the documentation for more information.
   'metamta.maniphest.public-create-email' => 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,
 
   // Maximum number of simultaneous web sessions each user is permitted to have.
   // Setting this to "1" will prevent a user from logging in on more than one
   // browser at the same time.
   'auth.sessions.web'           => 5,
 
   // Maximum number of simultaneous Conduit sessions each user is permitted
   // to have.
   'auth.sessions.conduit'       => 3,
 
 
 // -- 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,
 
 // -- 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 easily 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,
 
   // Array for custom remarkup rules. The array should have a list of
   // class names of classes that extend PhutilRemarkupRule
   'differential.custom-remarkup-rules' => null,
 
   // Array for custom remarkup block rules. The array should have a list of
   // class names of classes that extend PhutilRemarkupEngineBlockRule
   'differential.custom-remarkup-block-rules' => null,
 
   // Set display word-wrap widths for Differential. Specify a dictionary of
   // regular expressions mapping to column widths. The filename will be matched
   // against each regexp in order until one matches. The default configuration
   // uses a width of 100 for Java and 80 for other languages. Note that 80 is
   // the greatest column width of all time. Changes here will not be immediately
   // reflected in old revisions unless you purge the render cache.
   'differential.wordwrap' => array(
     '/\.java$/' => 100,
     '/.*/'      => 80,
   ),
 
   // Class for appending custom fields to be included in the commit
   // messages generated by "arc amend".  Should inherit
   // DifferentialCommitMessageModifier
   'differential.modify-commit-message-class' => null,
 
 
 // -- Maniphest ------------------------------------------------------------- //
 
   'maniphest.enabled' => true,
 
 // -- Remarkup -------------------------------------------------------------- //
 
   // If you enable this, linked YouTube videos will be embeded inline. This has
   // mild security implications (you'll leak referrers to YouTube) and is pretty
   // silly (but sort of awesome).
   'remarkup.enable-embedded-youtube' => false,
 
 
 // -- Garbage Collection ---------------------------------------------------- //
 
   // Phabricator generates various logs and caches in the database which can
   // be garbage collected after a while to make the total data size more
   // manageable. To run garbage collection, launch a
   // PhabricatorGarbageCollector daemon.
 
   // Since the GC daemon can issue large writes and table scans, you may want to
   // run it only during off hours or make sure it is scheduled so it doesn't
   // overlap with backups. This determines when the daemon can start running
   // each day.
   'gcdaemon.run-at'    => '12 AM',
 
   // How many seconds after 'gcdaemon.run-at' the daemon may collect garbage
   // for. By default it runs continuously, but you can set it to run for a
   // limited period of time. For instance, if you do backups at 3 AM, you might
   // run garbage collection for an hour beforehand. This is not a high-precision
   // limit so you may want to leave some room for the GC to actually stop, and
   // if you set it to something like 3 seconds you're on your own.
   'gcdaemon.run-for'   => 24 * 60 * 60,
 
   // These 'ttl' keys configure how much old data the GC daemon keeps around.
   // Objects older than the ttl will be collected. Set any value to 0 to store
   // data indefinitely.
 
   'gcdaemon.ttl.herald-transcripts'         => 30 * (24 * 60 * 60),
   'gcdaemon.ttl.daemon-logs'                =>  7 * (24 * 60 * 60),
   'gcdaemon.ttl.differential-render-cache'  =>  7 * (24 * 60 * 60),
 
 
 // -- 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',
 
   // In a development environment, it is desirable to force static resources
   // (CSS and JS) to be read from disk on every request, so that edits to them
   // appear when you reload the page even if you haven't updated the resource
   // maps. This setting ensures requests will be verified against the state on
   // disk. Generally, you should leave this off in production (caching behavior
   // and performance improve with it off) but turn it on in development. (These
   // settings are the defaults.)
   'celerity.force-disk-reads' => false,
 
   // -- Pygments ------------------------------------------------------------ //
   // 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,
 
   // In places that we display a dropdown to syntax-highlight code,
   // this is where that list is defined.
   // Syntax is 'lexer-name' => 'Display Name',
   'pygments.dropdown-choices' => array(
     'apacheconf' => 'Apache Configuration',
     'bash' => 'Bash Scripting',
     'brainfuck' => 'Brainf*ck',
     'c' => 'C',
     'cpp' => 'C++',
     'css' => 'CSS',
     'diff' => 'Diff',
     'django' => 'Django Templating',
     'erb' => 'Embedded Ruby/ERB',
     'erlang' => 'Erlang',
     'html' => 'HTML',
     'infer' => 'Infer from title (extension)',
     'java' => 'Java',
     'js' => 'Javascript',
     'mysql' => 'MySQL',
     'perl' => 'Perl',
     'php' => 'PHP',
     'text' => 'Plain Text',
     'python' => 'Python',
     // TODO: 'remarkup' => 'Remarkup',
     'ruby' => 'Ruby',
     'xml' => 'XML',
   ),
 
   'pygments.dropdown-default' => 'infer',
 
+  // This is an override list of regular expressions which allows you to choose
+  // what language files are highlighted as. If your projects have certain rules
+  // about filenames or use unusual or ambiguous language extensions, you can
+  // create a mapping here. This is an ordered dictionary of regular expressions
+  // which will be tested against the filename. They should map to either an
+  // explicit language as a string value, or a numeric index into the captured
+  // groups as an integer.
+  'syntax.filemap' => array(
+    // Example: Treat all '*.xyz' files as PHP.
+    // '@\\.xyz$@' => 'php',
+
+    // Example: Treat 'httpd.conf' as 'apacheconf'.
+    // '@/httpd\\.conf$@' => 'apacheconf',
+
+    // Example: Treat all '*.x.bak' file as '.x'. NOTE: we map to capturing
+    // group 1 by specifying the mapping as "1".
+    // '@\\.([^.]+)\\.bak$@' => 1,
+  ),
+
 );
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index f38452557..f2019e64c 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,1027 +1,1028 @@
 <?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',
     'AphrontAttachedFileView' => 'view/control/attachedfile',
     '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',
     'AphrontFilePreviewView' => 'view/layout/filepreview',
     'AphrontFileResponse' => 'aphront/response/file',
     'AphrontFormCheckboxControl' => 'view/form/control/checkbox',
     'AphrontFormControl' => 'view/form/control/base',
     'AphrontFormDividerControl' => 'view/form/control/divider',
     'AphrontFormDragAndDropUploadControl' => 'view/form/control/draganddropupload',
     'AphrontFormFileControl' => 'view/form/control/file',
     'AphrontFormLayoutView' => 'view/form/layout',
     '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__',
     'AphrontKeyboardShortcutsAvailableView' => 'view/widget/keyboardshortcuts',
     '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',
     'AphrontReloadResponse' => 'aphront/response/reload',
     '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_getcertificate_Method' => 'applications/conduit/method/conduit/getcertificate',
     '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_differential_updateunitresults_Method' => 'applications/conduit/method/differential/updateunitresults',
     'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits',
     'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/conduit/method/diffusion/getrecentcommitsbypath',
     'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download',
     'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
     'ConduitAPI_maniphest_info_Method' => 'applications/conduit/method/maniphest/info',
     'ConduitAPI_paste_info_Method' => 'applications/conduit/method/paste/info',
     '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',
     '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',
     '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',
     'DifferentialCommitMessageField' => 'applications/differential/data/commitmessage',
     'DifferentialCommitMessageModifier' => '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',
     'DifferentialPrimaryPaneView' => 'applications/differential/view/primarypane',
     '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',
     'DifferentialUnitTestResult' => 'applications/differential/constants/unittestresult',
     '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',
     'HeraldRepetitionPolicyConfig' => 'applications/herald/config/repetitionpolicy',
     '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__',
     'ManiphestConstants' => 'applications/maniphest/constants/base',
     'ManiphestController' => 'applications/maniphest/controller/base',
     'ManiphestDAO' => 'applications/maniphest/storage/base',
     'ManiphestReplyHandler' => 'applications/maniphest/replyhandler',
     'ManiphestTask' => 'applications/maniphest/storage/task',
     'ManiphestTaskDescriptionChangeController' => 'applications/maniphest/controller/descriptionchange',
     'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail',
     'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit',
     'ManiphestTaskListController' => 'applications/maniphest/controller/tasklist',
     'ManiphestTaskListView' => 'applications/maniphest/view/tasklist',
     'ManiphestTaskOwner' => 'applications/maniphest/constants/owner',
     'ManiphestTaskPriority' => 'applications/maniphest/constants/priority',
     'ManiphestTaskProject' => 'applications/maniphest/storage/taskproject',
     'ManiphestTaskQuery' => 'applications/maniphest/query',
     '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',
     'ManiphestView' => 'applications/maniphest/view/base',
     'Phabricator404Controller' => 'applications/base/controller/404',
     'PhabricatorAuthController' => 'applications/auth/controller/base',
     'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
     'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/token',
     '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',
     'PhabricatorConduitTokenController' => 'applications/conduit/controller/token',
     'PhabricatorController' => 'applications/base/controller/base',
     'PhabricatorCountdownController' => 'applications/countdown/controller/base',
     'PhabricatorCountdownDAO' => 'applications/countdown/storage/base',
     'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/delete',
     'PhabricatorCountdownEditController' => 'applications/countdown/controller/edit',
     'PhabricatorCountdownListController' => 'applications/countdown/controller/list',
     'PhabricatorCountdownViewController' => 'applications/countdown/controller/view',
     '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',
     'PhabricatorDisabledUserController' => 'applications/auth/controller/disabled',
     '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',
     'PhabricatorFileDropUploadController' => 'applications/files/controller/dropupload',
     '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',
     'PhabricatorFileTransformController' => 'applications/files/controller/transform',
     'PhabricatorFileURI' => 'applications/files/uri',
     'PhabricatorFileUploadController' => 'applications/files/controller/upload',
     'PhabricatorFileViewController' => 'applications/files/controller/view',
     'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector',
     'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing',
     'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector',
     'PhabricatorHelpController' => 'applications/help/controller/base',
     'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/keyboardshortcut',
     'PhabricatorIRCBot' => 'infrastructure/daemon/irc/bot',
     'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base',
     'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message',
     'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname',
     'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol',
     'PhabricatorImageTransformer' => 'applications/files/transform',
     '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',
     'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/sendgrid',
     'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/test',
     'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/base',
     'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
     'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
     'PhabricatorMetaMTADaemon' => 'applications/metamta/daemon/mta',
     'PhabricatorMetaMTAEmailBodyParser' => 'applications/metamta/parser',
     'PhabricatorMetaMTAEmailBodyParserTestCase' => 'applications/metamta/parser/__tests__',
     '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',
     'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/sendgridreceive',
     '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',
     'PhabricatorPaste' => 'applications/paste/storage/paste',
     'PhabricatorPasteController' => 'applications/paste/controller/base',
     'PhabricatorPasteCreateController' => 'applications/paste/controller/create',
     'PhabricatorPasteDAO' => 'applications/paste/storage/base',
     'PhabricatorPasteListController' => 'applications/paste/controller/list',
     'PhabricatorPasteViewController' => 'applications/paste/controller/view',
     'PhabricatorPeopleController' => 'applications/people/controller/base',
     'PhabricatorPeopleEditController' => 'applications/people/controller/edit',
     'PhabricatorPeopleListController' => 'applications/people/controller/list',
     'PhabricatorPeopleLogsController' => 'applications/people/controller/logs',
     'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
     'PhabricatorPeopleProfileEditController' => 'applications/people/controller/profileedit',
     'PhabricatorPreferencesController' => 'applications/preferences/controller/base',
     'PhabricatorProfileView' => 'view/layout/profile',
     'PhabricatorProject' => 'applications/project/storage/project',
     'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
     'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
     'PhabricatorProjectController' => 'applications/project/controller/base',
     'PhabricatorProjectCreateController' => 'applications/project/controller/create',
     'PhabricatorProjectDAO' => 'applications/project/storage/base',
     'PhabricatorProjectListController' => 'applications/project/controller/list',
     'PhabricatorProjectProfile' => 'applications/project/storage/profile',
     'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
     'PhabricatorProjectProfileEditController' => 'applications/project/controller/profileedit',
     'PhabricatorProjectStatus' => 'applications/project/constants/status',
     'PhabricatorProjectTransactionSearch' => 'applications/project/transactions/search',
     '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',
     'PhabricatorRemarkupRuleMention' => 'infrastructure/markup/remarkup/markuprule/mention',
     'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/remarkup/markuprule/objectname',
     'PhabricatorRemarkupRulePaste' => 'infrastructure/markup/remarkup/markuprule/paste',
     'PhabricatorRemarkupRuleProxyImage' => 'infrastructure/markup/remarkup/markuprule/proxyimage',
     'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/remarkup/markuprule/youtube',
     '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',
     'PhabricatorSearchAttachController' => 'applications/search/controller/attach',
     'PhabricatorSearchBaseController' => 'applications/search/controller/base',
     'PhabricatorSearchCommitIndexer' => 'applications/search/index/indexer/repository',
     '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',
     'PhabricatorSearchIndexController' => 'applications/search/controller/index',
     'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest',
     'PhabricatorSearchMySQLExecutor' => 'applications/search/execute/mysql',
     'PhabricatorSearchQuery' => 'applications/search/storage/query',
     'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
     'PhabricatorSearchResultView' => 'applications/search/view/searchresult',
     'PhabricatorSearchSelectController' => 'applications/search/controller/select',
     'PhabricatorSearchUserIndexer' => 'applications/search/index/indexer/user',
     'PhabricatorSetup' => 'infrastructure/setup',
     'PhabricatorStandardPageView' => 'view/page/standard',
     'PhabricatorStatusController' => 'applications/status/base',
+    'PhabricatorSyntaxHighlighter' => 'applications/markup/syntax',
     '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',
     'PhabricatorTimer' => 'applications/countdown/storage/timer',
     'PhabricatorTransformedFile' => 'applications/files/storage/transformed',
     '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',
     'PhabricatorUserLog' => 'applications/people/storage/log',
     '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_date' => 'view/utils',
     'phabricator_datetime' => 'view/utils',
     'phabricator_format_relative_time' => 'view/utils',
     'phabricator_format_timestamp' => 'view/utils',
     'phabricator_format_units_generic' => 'view/utils',
     'phabricator_render_form' => 'infrastructure/javelin/markup',
     'phabricator_time' => 'view/utils',
     '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',
     'AphrontAttachedFileView' => 'AphrontView',
     'AphrontCrumbsView' => 'AphrontView',
     'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
     'AphrontDefaultApplicationController' => 'AphrontController',
     'AphrontDialogResponse' => 'AphrontResponse',
     'AphrontDialogView' => 'AphrontView',
     'AphrontErrorView' => 'AphrontView',
     'AphrontFilePreviewView' => 'AphrontView',
     'AphrontFileResponse' => 'AphrontResponse',
     'AphrontFormCheckboxControl' => 'AphrontFormControl',
     'AphrontFormControl' => 'AphrontView',
     'AphrontFormDividerControl' => 'AphrontFormControl',
     'AphrontFormDragAndDropUploadControl' => 'AphrontFormControl',
     'AphrontFormFileControl' => 'AphrontFormControl',
     'AphrontFormLayoutView' => 'AphrontView',
     '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',
     'AphrontKeyboardShortcutsAvailableView' => 'AphrontView',
     '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',
     'AphrontReloadResponse' => 'AphrontRedirectResponse',
     'AphrontRequestFailureView' => 'AphrontView',
     'AphrontSideNavView' => 'AphrontView',
     'AphrontTableView' => 'AphrontView',
     'AphrontTokenizerTemplateView' => 'AphrontView',
     'AphrontTypeaheadTemplateView' => 'AphrontView',
     'AphrontWebpageResponse' => 'AphrontResponse',
     'CelerityResourceController' => 'AphrontController',
     'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
     'ConduitAPI_conduit_getcertificate_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_differential_updateunitresults_Method' => 'ConduitAPIMethod',
     'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod',
     'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_download_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
     'ConduitAPI_maniphest_info_Method' => 'ConduitAPIMethod',
     'ConduitAPI_paste_info_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',
     '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',
     'DifferentialPrimaryPaneView' => 'AphrontView',
     'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler',
     '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',
     'ManiphestReplyHandler' => 'PhabricatorMailReplyHandler',
     'ManiphestTask' => 'ManiphestDAO',
     'ManiphestTaskDescriptionChangeController' => 'ManiphestController',
     'ManiphestTaskDetailController' => 'ManiphestController',
     'ManiphestTaskEditController' => 'ManiphestController',
     'ManiphestTaskListController' => 'ManiphestController',
     'ManiphestTaskListView' => 'ManiphestView',
     'ManiphestTaskOwner' => 'ManiphestConstants',
     'ManiphestTaskPriority' => 'ManiphestConstants',
     'ManiphestTaskProject' => 'ManiphestDAO',
     'ManiphestTaskStatus' => 'ManiphestConstants',
     'ManiphestTaskSummaryView' => 'ManiphestView',
     'ManiphestTransaction' => 'ManiphestDAO',
     'ManiphestTransactionDetailView' => 'ManiphestView',
     'ManiphestTransactionListView' => 'ManiphestView',
     'ManiphestTransactionPreviewController' => 'ManiphestController',
     'ManiphestTransactionSaveController' => 'ManiphestController',
     'ManiphestTransactionType' => 'ManiphestConstants',
     'ManiphestView' => 'AphrontView',
     'Phabricator404Controller' => 'PhabricatorController',
     'PhabricatorAuthController' => 'PhabricatorController',
     'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
     'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
     'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
     'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
     'PhabricatorConduitController' => 'PhabricatorController',
     'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
     'PhabricatorConduitLogController' => 'PhabricatorConduitController',
     'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
     'PhabricatorConduitTokenController' => 'PhabricatorConduitController',
     'PhabricatorController' => 'AphrontController',
     'PhabricatorCountdownController' => 'PhabricatorController',
     'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO',
     'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController',
     'PhabricatorCountdownEditController' => 'PhabricatorCountdownController',
     'PhabricatorCountdownListController' => 'PhabricatorCountdownController',
     'PhabricatorCountdownViewController' => 'PhabricatorCountdownController',
     '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',
     'PhabricatorDisabledUserController' => 'PhabricatorAuthController',
     'PhabricatorDraft' => 'PhabricatorDraftDAO',
     'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
     'PhabricatorEditPreferencesController' => 'PhabricatorPreferencesController',
     'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
     'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
     'PhabricatorFile' => 'PhabricatorFileDAO',
     'PhabricatorFileController' => 'PhabricatorController',
     'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
     'PhabricatorFileImageMacro' => 'PhabricatorFileDAO',
     'PhabricatorFileListController' => 'PhabricatorFileController',
     'PhabricatorFileMacroDeleteController' => 'PhabricatorFileController',
     'PhabricatorFileMacroEditController' => 'PhabricatorFileController',
     'PhabricatorFileMacroListController' => 'PhabricatorFileController',
     'PhabricatorFileProxyController' => 'PhabricatorFileController',
     'PhabricatorFileProxyImage' => 'PhabricatorFileDAO',
     'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
     'PhabricatorFileTransformController' => 'PhabricatorFileController',
     'PhabricatorFileUploadController' => 'PhabricatorFileController',
     'PhabricatorFileViewController' => 'PhabricatorFileController',
     'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon',
     'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker',
     'PhabricatorHelpController' => 'PhabricatorController',
     'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
     'PhabricatorIRCBot' => 'PhabricatorDaemon',
     'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler',
     'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler',
     'PhabricatorJavelinLinter' => 'ArcanistLinter',
     'PhabricatorLintEngine' => 'PhutilLintEngine',
     'PhabricatorLiskDAO' => 'LiskDAO',
     'PhabricatorLoginController' => 'PhabricatorAuthController',
     'PhabricatorLogoutController' => 'PhabricatorAuthController',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMetaMTAController' => 'PhabricatorController',
     'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
     'PhabricatorMetaMTADaemon' => 'PhabricatorDaemon',
     'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase',
     'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase',
     'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAReceiveController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAReceivedListController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTASendGridReceiveController' => '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',
     'PhabricatorPaste' => 'PhabricatorPasteDAO',
     'PhabricatorPasteController' => 'PhabricatorController',
     'PhabricatorPasteCreateController' => 'PhabricatorPasteController',
     'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
     'PhabricatorPasteListController' => 'PhabricatorPasteController',
     'PhabricatorPasteViewController' => 'PhabricatorPasteController',
     'PhabricatorPeopleController' => 'PhabricatorController',
     'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController',
     'PhabricatorPreferencesController' => 'PhabricatorController',
     'PhabricatorProfileView' => 'AphrontView',
     'PhabricatorProject' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectController' => 'PhabricatorController',
     'PhabricatorProjectCreateController' => 'PhabricatorProjectController',
     'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
     'PhabricatorProjectListController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
     'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
     'PhabricatorRedirectController' => 'PhabricatorController',
     'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName',
     'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleManiphest' => 'PhabricatorRemarkupRuleObjectName',
     'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRulePaste' => 'PhabricatorRemarkupRuleObjectName',
     'PhabricatorRemarkupRuleProxyImage' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleYoutube' => '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',
     'PhabricatorSearchAttachController' => 'PhabricatorSearchController',
     'PhabricatorSearchBaseController' => 'PhabricatorController',
     'PhabricatorSearchCommitIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
     'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO',
     'PhabricatorSearchIndexController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor',
     'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
     'PhabricatorSearchResultView' => 'AphrontView',
     'PhabricatorSearchSelectController' => 'PhabricatorSearchController',
     'PhabricatorSearchUserIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorStandardPageView' => 'AphrontPageView',
     'PhabricatorStatusController' => 'PhabricatorController',
     'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon',
     'PhabricatorTestCase' => 'ArcanistPhutilTestCase',
     'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
     'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
     'PhabricatorTimer' => 'PhabricatorCountdownDAO',
     'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
     'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
     'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
     'PhabricatorUIExampleController' => 'PhabricatorController',
     'PhabricatorUIExampleRenderController' => 'PhabricatorUIExampleController',
     'PhabricatorUIListFilterExample' => 'PhabricatorUIExample',
     'PhabricatorUIPagerExample' => 'PhabricatorUIExample',
     'PhabricatorUser' => 'PhabricatorUserDAO',
     'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
     'PhabricatorUserLog' => 'PhabricatorUserDAO',
     '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/applications/differential/parser/changeset/DifferentialChangesetParser.php b/src/applications/differential/parser/changeset/DifferentialChangesetParser.php
index edc6153d0..c43aaf9ec 100644
--- a/src/applications/differential/parser/changeset/DifferentialChangesetParser.php
+++ b/src/applications/differential/parser/changeset/DifferentialChangesetParser.php
@@ -1,1602 +1,1599 @@
 <?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 DifferentialChangesetParser {
 
   protected $visible      = array();
   protected $new          = array();
   protected $old          = array();
   protected $intra        = array();
   protected $newRender    = null;
   protected $oldRender    = null;
   protected $parsedHunk   = false;
 
   protected $filename     = null;
   protected $missingOld   = array();
   protected $missingNew   = array();
 
   protected $comments     = array();
   protected $specialAttributes = array();
 
   protected $changeset;
   protected $whitespaceMode = null;
 
   protected $subparser;
 
   protected $renderCacheKey = null;
 
   private $handles;
   private $user;
 
   private $leftSideChangesetID;
   private $leftSideAttachesToNewFile;
 
   private $rightSideChangesetID;
   private $rightSideAttachesToNewFile;
 
   private $renderingReference;
   private $isSubparser;
 
   private $lineWidth = 80;
   private $isTopLevel;
 
   const CACHE_VERSION = 4;
 
   const ATTR_GENERATED  = 'attr:generated';
   const ATTR_DELETED    = 'attr:deleted';
   const ATTR_UNCHANGED  = 'attr:unchanged';
   const ATTR_WHITELINES = 'attr:white';
 
   const LINES_CONTEXT = 8;
 
   const WHITESPACE_SHOW_ALL         = 'show-all';
   const WHITESPACE_IGNORE_TRAILING  = 'ignore-trailing';
   const WHITESPACE_IGNORE_ALL       = 'ignore-all';
 
   /**
    * Configure which Changeset comments added to the right side of the visible
    * diff will be attached to. The ID must be the ID of a real Differential
    * Changeset.
    *
    * The complexity here is that we may show an arbitrary side of an arbitrary
    * changeset as either the left or right part of a diff. This method allows
    * the left and right halves of the displayed diff to be correctly mapped to
    * storage changesets.
    *
    * @param id    The Differential Changeset ID that comments added to the right
    *              side of the visible diff should be attached to.
    * @param bool  If true, attach new comments to the right side of the storage
    *              changeset. Note that this may be false, if the left side of
    *              some storage changeset is being shown as the right side of
    *              a display diff.
    * @return this
    */
   public function setRightSideCommentMapping($id, $is_new) {
     $this->rightSideChangesetID = $id;
     $this->rightSideAttachesToNewFile = $is_new;
     return $this;
   }
 
   /**
    * See setRightSideCommentMapping(), but this sets information for the left
    * side of the display diff.
    */
   public function setLeftSideCommentMapping($id, $is_new) {
     $this->leftSideChangesetID = $id;
     $this->leftSideAttachesToNewFile = $is_new;
     return $this;
   }
 
   /**
    * Set a key for identifying this changeset in the render cache. If set, the
    * parser will attempt to use the changeset render cache, which can improve
    * performance for frequently-viewed changesets.
    *
    * By default, there is no render cache key and parsers do not use the cache.
    * This is appropriate for rarely-viewed changesets.
    *
    * NOTE: Currently, this key must be a valid Differential Changeset ID.
    *
    * @param   string  Key for identifying this changeset in the render cache.
    * @return  this
    */
   public function setRenderCacheKey($key) {
     $this->renderCacheKey = $key;
     return $this;
   }
 
   /**
    * Set the character width at which lines will be wrapped. Defaults to 80.
    *
    * @param   int Hard-wrap line-width for diff display.
    * @return this
    */
   public function setLineWidth($width) {
     $this->lineWidth = $width;
     return $this;
   }
 
   private function getRenderCacheKey() {
     return $this->renderCacheKey;
   }
 
   public function setChangeset($changeset) {
     $this->changeset = $changeset;
 
     $this->setFilename($changeset->getFilename());
     $this->setLineWidth($changeset->getWordWrapWidth());
 
     return $this;
   }
 
   public function setWhitespaceMode($whitespace_mode) {
     $this->whitespaceMode = $whitespace_mode;
     return $this;
   }
 
   public function setRenderingReference($ref) {
     $this->renderingReference = $ref;
     return $this;
   }
 
   public function getChangeset() {
     return $this->changeset;
   }
 
   public function setFilename($filename) {
     $this->filename = $filename;
     return $this;
   }
 
   public function setHandles(array $handles) {
     $this->handles = $handles;
     return $this;
   }
 
   public function setMarkupEngine(PhutilMarkupEngine $engine) {
     $this->markupEngine = $engine;
     return $this;
   }
 
   public function setUser(PhabricatorUser $user) {
     $this->user = $user;
     return $this;
   }
 
   public function parseHunk(DifferentialHunk $hunk) {
     $this->parsedHunk = true;
     $lines = $hunk->getChanges();
 
     $lines = str_replace(
       array("\t", "\r\n", "\r"),
       array('  ', "\n",   "\n"),
       $lines);
     $lines = explode("\n", $lines);
 
     $types = array();
     foreach ($lines as $line_index => $line) {
       if (isset($line[0])) {
         $char = $line[0];
         if ($char == ' ') {
           $types[$line_index] = null;
         } else if ($char == '\\' && $line_index > 0) {
           $types[$line_index] = $types[$line_index - 1];
         } else {
           $types[$line_index] = $char;
         }
       } else {
         $types[$line_index] = null;
       }
     }
 
     $old_line = $hunk->getOldOffset();
     $new_line = $hunk->getNewOffset();
     $num_lines = count($lines);
 
     if ($old_line > 1) {
       $this->missingOld[$old_line] = true;
     } else if ($new_line > 1) {
       $this->missingNew[$new_line] = true;
     }
 
     for ($cursor = 0; $cursor < $num_lines; $cursor++) {
       $type = $types[$cursor];
       $data = array(
         'type'  => $type,
         'text'  => (string)substr($lines[$cursor], 1),
         'line'  => $new_line,
       );
       switch ($type) {
         case '+':
           $this->new[] = $data;
           ++$new_line;
           break;
         case '-':
           $data['line'] = $old_line;
           $this->old[] = $data;
           ++$old_line;
           break;
         default:
           $this->new[] = $data;
           $data['line'] = $old_line;
           $this->old[] = $data;
           ++$new_line;
           ++$old_line;
           break;
       }
     }
   }
 
   public function getDisplayLine($offset, $length) {
     $start = 1;
     for ($ii = $offset; $ii > 0; $ii--) {
       if ($this->new[$ii] && $this->new[$ii]['line']) {
         $start = $this->new[$ii]['line'];
         break;
       }
     }
     $end = $start;
     for ($ii = $offset + $length; $ii < count($this->new); $ii++) {
       if ($this->new[$ii] && $this->new[$ii]['line']) {
         $end = $this->new[$ii]['line'];
         break;
       }
     }
     return "{$start},{$end}";
   }
 
   public function parseInlineComment(DifferentialInlineComment $comment) {
     // Parse only comments which are actually visible.
     if ($this->isCommentVisibleOnRenderedDiff($comment)) {
       $this->comments[] = $comment;
     }
     return $this;
   }
 
   public function process() {
 
     $old = array();
     $new = array();
 
     $n = 0;
 
     $this->old = array_reverse($this->old);
     $this->new = array_reverse($this->new);
 
     $whitelines = false;
     $changed = false;
 
     $skip_intra = array();
     while (count($this->old) || count($this->new)) {
       $o_desc = array_pop($this->old);
       $n_desc = array_pop($this->new);
 
       $oend = end($this->old);
       if ($oend) {
         $o_next = $oend['type'];
       } else {
         $o_next = null;
       }
 
       $nend = end($this->new);
       if ($nend) {
         $n_next = $nend['type'];
       } else {
         $n_next = null;
       }
 
       if ($o_desc) {
         $o_type = $o_desc['type'];
       } else {
         $o_type = null;
       }
 
       if ($n_desc) {
         $n_type = $n_desc['type'];
       } else {
         $n_type = null;
       }
 
       if (($o_type != null) && ($n_type == null)) {
         $old[] = $o_desc;
         $new[] = null;
         if ($n_desc) {
           array_push($this->new, $n_desc);
         }
         $changed = true;
         continue;
       }
 
       if (($n_type != null) && ($o_type == null)) {
         $old[] = null;
         $new[] = $n_desc;
         if ($o_desc) {
           array_push($this->old, $o_desc);
         }
         $changed = true;
         continue;
       }
 
       if ($this->whitespaceMode != self::WHITESPACE_SHOW_ALL) {
         $similar = false;
         switch ($this->whitespaceMode) {
           case self::WHITESPACE_IGNORE_TRAILING:
             if (rtrim($o_desc['text']) == rtrim($n_desc['text'])) {
               if ($o_desc['type']) {
                 // If we're converting this into an unchanged line because of
                 // a trailing whitespace difference, mark it as a whitespace
                 // change so we can show "This file was modified only by
                 // adding or removing trailing whitespace." instead of
                 // "This file was not modified.".
                 $whitelines = true;
               }
               $similar = true;
             }
             break;
           default:
             // In this case, the lines are similar if there is no change type
             // (that is, just trust the diff algorithm).
             if (!$o_desc['type']) {
               $similar = true;
             }
             break;
         }
         if ($similar) {
           $o_desc['type'] = null;
           $n_desc['type'] = null;
           $skip_intra[count($old)] = true;
         } else {
           $changed = true;
         }
       } else {
         $changed = true;
       }
 
       $old[] = $o_desc;
       $new[] = $n_desc;
     }
 
     $this->old = $old;
     $this->new = $new;
 
     $unchanged = false;
     if ($this->subparser) {
       $unchanged = $this->subparser->isUnchanged();
       $whitelines = $this->subparser->isWhitespaceOnly();
     } else if (!$changed) {
       $filetype = $this->changeset->getFileType();
       if ($filetype == DifferentialChangeType::FILE_TEXT ||
           $filetype == DifferentialChangeType::FILE_SYMLINK) {
         $unchanged = true;
       }
     }
 
     $this->specialAttributes = array(
       self::ATTR_UNCHANGED  => $unchanged,
       self::ATTR_DELETED    => array_filter($this->old) &&
                                !array_filter($this->new),
       self::ATTR_WHITELINES => $whitelines
     );
 
     if ($this->isSubparser) {
       // The rest of this function deals with formatting the diff for display;
       // we can exit early if we're a subparser and avoid doing extra work.
       return;
     }
 
     if ($this->subparser) {
 
       // Use this parser's side-by-side line information -- notably, the
       // change types -- but replace all the line text with the subparser's.
       // This lets us render whitespace-only changes without marking them as
       // different.
 
       $old = $this->old;
       $new = $this->new;
       $old_text = ipull($this->subparser->old, 'text', 'line');
       $new_text = ipull($this->subparser->new, 'text', 'line');
 
       foreach ($old as $k => $desc) {
         if (empty($desc)) {
           continue;
         }
         $old[$k]['text'] = idx($old_text, $desc['line']);
       }
       foreach ($new as $k => $desc) {
         if (empty($desc)) {
           continue;
         }
         $new[$k]['text'] = idx($new_text, $desc['line']);
 
         // If there's a corresponding "old" text and the line is marked as
         // unchanged, test if there are internal whitespace changes between
         // non-whitespace characters, e.g. spaces added to a string or spaces
         // added around operators. If we find internal spaces, mark the line
         // as changed.
         //
         // We only need to do this for "new" lines because any line that is
         // missing either "old" or "new" text certainly can not have internal
         // whitespace changes without also having non-whitespace changes,
         // because characters had to be either added or removed to create the
         // possibility of internal whitespace.
         if (isset($old[$k]['text']) && empty($new[$k]['type'])) {
           if (trim($old[$k]['text']) != trim($new[$k]['text'])) {
             // The strings aren't the same when trimmed, so there are internal
             // whitespace changes. Mark this line changed.
             $old[$k]['type'] = '-';
             $new[$k]['type'] = '+';
           }
         }
       }
 
       $this->old = $old;
       $this->new = $new;
     }
 
     $min_length = min(count($this->old), count($this->new));
     for ($ii = 0; $ii < $min_length; $ii++) {
       if ($this->old[$ii] || $this->new[$ii]) {
         if (isset($this->old[$ii]['text'])) {
           $otext = $this->old[$ii]['text'];
         } else {
           $otext = '';
         }
         if (isset($this->new[$ii]['text'])) {
           $ntext = $this->new[$ii]['text'];
         } else {
           $ntext = '';
         }
         if ($otext != $ntext && empty($skip_intra[$ii])) {
           $this->intra[$ii] = ArcanistDiffUtils::generateIntralineDiff(
             $otext,
             $ntext);
         }
       }
     }
 
     $lines_context = self::LINES_CONTEXT;
     $max_length = max(count($this->old), count($this->new));
     $old = $this->old;
     $new = $this->new;
     $visible = false;
     $last = 0;
     for ($cursor = -$lines_context; $cursor < $max_length; $cursor++) {
       $offset = $cursor + $lines_context;
       if ((isset($old[$offset]) && $old[$offset]['type']) ||
           (isset($new[$offset]) && $new[$offset]['type'])) {
         $visible = true;
         $last = $offset;
       } else if ($cursor > $last + $lines_context) {
         $visible = false;
       }
       if ($visible && $cursor > 0) {
         $this->visible[$cursor] = 1;
       }
     }
 
     $old_corpus = ipull($this->old, 'text');
     $old_corpus_block = implode("\n", $old_corpus);
 
     $new_corpus = ipull($this->new, 'text');
     $new_corpus_block = implode("\n", $new_corpus);
 
     $old_future = $this->getHighlightFuture($old_corpus_block);
     $new_future = $this->getHighlightFuture($new_corpus_block);
     $futures = array(
       'old' => $old_future,
       'new' => $new_future,
     );
     foreach (Futures($futures) as $key => $future) {
       try {
         switch ($key) {
           case 'old':
             $this->oldRender = $this->processHighlightedSource(
               $this->old,
               $future->resolve());
             break;
           case 'new':
             $this->newRender = $this->processHighlightedSource(
               $this->new,
               $future->resolve());
             break;
         }
       } catch (Exception $ex) {
         phlog($ex);
         throw $ex;
       }
     }
 
     $this->applyIntraline(
       $this->oldRender,
       ipull($this->intra, 0),
       $old_corpus);
     $this->applyIntraline(
       $this->newRender,
       ipull($this->intra, 1),
       $new_corpus);
 
     $generated = (strpos($new_corpus_block, '@'.'generated') !== false);
 
     $this->specialAttributes[self::ATTR_GENERATED] = $generated;
   }
 
   public function loadCache() {
     $render_cache_key = $this->getRenderCacheKey();
     if (!$render_cache_key) {
       return false;
     }
 
     $data = null;
 
     $changeset = new DifferentialChangeset();
     $conn_r = $changeset->establishConnection('r');
     $data = queryfx_one(
       $conn_r,
       'SELECT * FROM %T WHERE id = %d',
       $changeset->getTableName().'_parse_cache',
       $render_cache_key);
 
     if (!$data) {
       return false;
     }
 
     $data = json_decode($data['cache'], true);
     if (!is_array($data) || !$data) {
       return false;
     }
 
     foreach (self::getCacheableProperties() as $cache_key) {
       if (!array_key_exists($cache_key, $data)) {
         // If we're missing a cache key, assume we're looking at an old cache
         // and ignore it.
         return false;
       }
     }
 
     if ($data['cacheVersion'] !== self::CACHE_VERSION) {
       return false;
     }
 
     unset($data['cacheVersion'], $data['cacheHost']);
     $cache_prop = array_select_keys($data, self::getCacheableProperties());
     foreach ($cache_prop as $cache_key => $v) {
       $this->$cache_key = $v;
     }
 
     return true;
   }
 
   protected static function getCacheableProperties() {
     return array(
       'visible',
       'new',
       'old',
       'intra',
       'newRender',
       'oldRender',
       'specialAttributes',
       'missingOld',
       'missingNew',
       'cacheVersion',
       'cacheHost',
     );
   }
 
   public function saveCache() {
     $render_cache_key = $this->getRenderCacheKey();
     if (!$render_cache_key) {
       return false;
     }
 
     $cache = array();
     foreach (self::getCacheableProperties() as $cache_key) {
       switch ($cache_key) {
         case 'cacheVersion':
           $cache[$cache_key] = self::CACHE_VERSION;
           break;
         case 'cacheHost':
           $cache[$cache_key] = php_uname('n');
           break;
         default:
           $cache[$cache_key] = $this->$cache_key;
           break;
       }
     }
     $cache = json_encode($cache);
 
     try {
       $changeset = new DifferentialChangeset();
       $conn_w = $changeset->establishConnection('w');
       queryfx(
         $conn_w,
         'INSERT INTO %T (id, cache) VALUES (%d, %s)
           ON DUPLICATE KEY UPDATE cache = VALUES(cache)',
         $changeset->getTableName().'_parse_cache',
         $render_cache_key,
         $cache);
     } catch (AphrontQueryException $ex) {
       // TODO: uhoh
     }
   }
 
   public function isGenerated() {
     return idx($this->specialAttributes, self::ATTR_GENERATED, false);
   }
 
   public function isDeleted() {
     return idx($this->specialAttributes, self::ATTR_DELETED, false);
   }
 
   public function isUnchanged() {
     return idx($this->specialAttributes, self::ATTR_UNCHANGED, false);
   }
 
   public function isWhitespaceOnly() {
     return idx($this->specialAttributes, self::ATTR_WHITELINES, false);
   }
 
   public function getLength() {
     return max(count($this->old), count($this->new));
   }
 
   protected function applyIntraline(&$render, $intra, $corpus) {
     foreach ($render as $key => $text) {
       if (isset($intra[$key])) {
         $render[$key] = ArcanistDiffUtils::applyIntralineDiff(
           $text,
           $intra[$key]);
       }
       if (isset($corpus[$key]) && strlen($corpus[$key]) > $this->lineWidth) {
         $render[$key] = $this->lineWrap($render[$key]);
       }
     }
   }
 
   /**
    * Hard-wrap a piece of UTF-8 text with embedded HTML tags and entities.
    *
    * @param   string An HTML string with tags and entities.
    * @return  string Hard-wrapped string.
    */
   protected function lineWrap($line) {
     $c = 0;
     $break_here = array();
 
     // Convert the UTF-8 string into a list of UTF-8 characters.
     $vector = phutil_utf8v($line);
     $len = count($vector);
     $byte_pos = 0;
     for ($ii = 0; $ii < $len; ++$ii) {
       // An ampersand indicates an HTML entity; consume the whole thing (until
       // ";") but treat it all as one character.
       if ($vector[$ii] == '&') {
         do {
           ++$ii;
         } while ($vector[$ii] != ';');
         ++$c;
       // An "<" indicates an HTML tag, consume the whole thing but don't treat
       // it as a character.
       } else if ($vector[$ii] == '<') {
         do {
           ++$ii;
         } while ($vector[$ii] != '>');
       } else {
         ++$c;
       }
 
       // Keep track of where we need to break the string later.
       if ($c == $this->lineWidth) {
         $break_here[$ii] = true;
         $c = 0;
       }
     }
 
     $result = array();
     foreach ($vector as $ii => $char) {
       $result[] = $char;
       if (isset($break_here[$ii])) {
         $result[] = "<span class=\"over-the-line\">\xE2\xAC\x85</span><br />";
       }
     }
 
     return implode('', $result);
   }
 
   protected function getHighlightFuture($corpus) {
     return $this->highlightEngine->getHighlightFuture(
       $this->highlightEngine->getLanguageFromFilename($this->filename),
       $corpus);
   }
 
   protected function processHighlightedSource($data, $result) {
 
     $result_lines = explode("\n", $result);
     foreach ($data as $key => $info) {
       if (!$info) {
         unset($result_lines[$key]);
       }
     }
     return $result_lines;
   }
 
   private function tryCacheStuff() {
     $whitespace_mode = $this->whitespaceMode;
     switch ($whitespace_mode) {
       case self::WHITESPACE_SHOW_ALL:
       case self::WHITESPACE_IGNORE_TRAILING:
         break;
       default:
         $whitespace_mode = self::WHITESPACE_IGNORE_ALL;
         break;
     }
 
     $skip_cache = ($whitespace_mode != self::WHITESPACE_IGNORE_ALL);
     $this->whitespaceMode = $whitespace_mode;
 
     $changeset = $this->changeset;
 
     if ($changeset->getFileType() == DifferentialChangeType::FILE_TEXT ||
         $changeset->getFileType() == DifferentialChangeType::FILE_SYMLINK) {
       if ($skip_cache || !$this->loadCache()) {
 
         $ignore_all = ($this->whitespaceMode == self::WHITESPACE_IGNORE_ALL);
 
         // The "ignore all whitespace" algorithm depends on rediffing the
         // files, and we currently need complete representations of both
         // files to do anything reasonable. If we only have parts of the files,
         // don't use the "ignore all" algorithm.
         if ($ignore_all) {
           $hunks = $changeset->getHunks();
           if (count($hunks) !== 1) {
             $ignore_all = false;
           } else {
             $first_hunk = reset($hunks);
             if ($first_hunk->getOldOffset() != 1 ||
                 $first_hunk->getNewOffset() != 1) {
               $ignore_all = false;
             }
           }
         }
 
         if ($ignore_all) {
           $old_file = $changeset->makeOldFile();
           $new_file = $changeset->makeNewFile();
           if ($old_file == $new_file) {
             // If the old and new files are exactly identical, the synthetic
             // diff below will give us nonsense and whitespace modes are
             // irrelevant anyway. This occurs when you, e.g., copy a file onto
             // itself in Subversion (see T271).
             $ignore_all = false;
           }
         }
 
         if ($ignore_all) {
 
           // Huge mess. Generate a "-bw" (ignore all whitespace changes) diff,
           // parse it out, and then play a shell game with the parsed format
           // in process() so we highlight only changed lines but render
           // whitespace differences. If we don't do this, we either fail to
           // render whitespace changes (which is incredibly confusing,
           // especially for python) or often produce a much larger set of
           // differences than necessary.
 
           $old_tmp = new TempFile();
           $new_tmp = new TempFile();
           Filesystem::writeFile($old_tmp, $old_file);
           Filesystem::writeFile($new_tmp, $new_file);
           list($err, $diff) = exec_manual(
             'diff -bw -U65535 %s %s       ',
             $old_tmp,
             $new_tmp);
 
           if (!strlen($diff)) {
             // If there's no diff text, that means the files are identical
             // except for whitespace changes. Build a synthetic, changeless
             // diff. TODO: this is incredibly hacky.
             $entire_file = explode("\n", $changeset->makeOldFile());
             foreach ($entire_file as $k => $line) {
               $entire_file[$k] = ' '.$line;
             }
             $len = count($entire_file);
             $entire_file = implode("\n", $entire_file);
 
             $diff = <<<EOSYNTHETIC
 --- ignored 9999-99-99
 +++ ignored 9999-99-99
 @@ -{$len},{$len} +{$len},{$len} @@
 {$entire_file}
 EOSYNTHETIC;
           }
 
           // subparser takes over the current non-whitespace-ignoring changeset
           $subparser = new DifferentialChangesetParser();
           $subparser->isSubparser = true;
           $subparser->setChangeset($changeset);
           foreach ($changeset->getHunks() as $hunk) {
             $subparser->parseHunk($hunk);
           }
           // We need to call process() so that the subparser's values for
           // things like.
           $subparser->process();
 
           $this->subparser = $subparser;
 
           // this parser takes new changeset; will use subparser's text later
           $changes = id(new ArcanistDiffParser())->parseDiff($diff);
           $diff = DifferentialDiff::newFromRawChanges($changes);
 
           // While we aren't updating $this->changeset (since it has a bunch
           // of metadata we need to preserve, so that headers like "this file
           // was moved" render correctly), we're overwriting the local
           // $changeset so that the block below will choose the synthetic
           // hunks we've built instead of the original hunks.
           $changeset = head($diff->getChangesets());
         }
 
         // This either uses the real hunks, or synthetic hunks we built above.
         foreach ($changeset->getHunks() as $hunk) {
           $this->parseHunk($hunk);
         }
         $this->process();
         if (!$skip_cache) {
           $this->saveCache();
         }
       }
     }
   }
 
   public function render(
     $range_start  = null,
     $range_len    = null,
     $mask_force   = array()) {
 
 
     // "Top level" renders are initial requests for the whole file, versus
     // requests for a specific range generated by clicking "show more". We
     // generate property changes and "shield" UI elements only for toplevel
     // requests.
     $this->isTopLevel = (($range_start === null) && ($range_len === null));
 
 
-    $this->highlightEngine = new PhutilDefaultSyntaxHighlighterEngine();
-    $this->highlightEngine->setConfig(
-      'pygments.enabled',
-      PhabricatorEnv::getEnvConfig('pygments.enabled'));
+    $this->highlightEngine = PhabricatorSyntaxHighlighter::newEngine();
 
     $this->tryCacheStuff();
 
     $feedback_mask = array();
 
     switch ($this->changeset->getFileType()) {
       case DifferentialChangeType::FILE_IMAGE:
         $old = null;
         $cur = null;
 
         $metadata = $this->changeset->getMetadata();
         $data = idx($metadata, 'attachment-data');
 
         $old_phid = idx($metadata, 'old:binary-phid');
         $new_phid = idx($metadata, 'new:binary-phid');
         if ($old_phid || $new_phid) {
           if ($old_phid) {
             $old_uri = PhabricatorFileURI::getViewURIForPHID($old_phid);
             $old = phutil_render_tag(
               'img',
               array(
                 'src' => $old_uri,
               ));
           }
           if ($new_phid) {
             $new_uri = PhabricatorFileURI::getViewURIForPHID($new_phid);
             $cur = phutil_render_tag(
               'img',
               array(
                 'src' => $new_uri,
               ));
           }
         }
 
         $output = $this->renderChangesetTable(
           $this->changeset,
           '<tr>'.
             '<th></th>'.
             '<td class="differential-old-image">'.
               '<div class="differential-image-stage">'.
                 $old.
               '</div>'.
             '</td>'.
             '<th></th>'.
             '<td class="differential-new-image">'.
               '<div class="differential-image-stage">'.
                 $cur.
               '</div>'.
             '</td>'.
           '</tr>');
 
         return $output;
       case DifferentialChangeType::FILE_DIRECTORY:
       case DifferentialChangeType::FILE_BINARY:
         $output = $this->renderChangesetTable($this->changeset, null);
         return $output;
     }
 
     $shield = null;
     if ($this->isTopLevel && !$this->comments) {
       if ($this->isGenerated()) {
         $shield = $this->renderShield(
           "This file contains generated code, which does not normally need ".
           "to be reviewed.",
           true);
       } else if ($this->isUnchanged()) {
         if ($this->isWhitespaceOnly()) {
           $shield = $this->renderShield(
             "This file was changed only by adding or removing trailing ".
             "whitespace.",
             false);
         } else {
           $shield = $this->renderShield(
             "The contents of this file were not changed.",
             false);
         }
       } else if ($this->isDeleted()) {
         $shield = $this->renderShield(
           "This file was completely deleted.",
           true);
       } else if ($this->changeset->getAffectedLineCount() > 2500) {
         $lines = number_format($this->changeset->getAffectedLineCount());
         $shield = $this->renderShield(
           "This file has a very large number of changes ({$lines} lines).",
           true);
       }
     }
 
     if ($shield) {
       return $this->renderChangesetTable($this->changeset, $shield);
     }
 
     $old_comments = array();
     $new_comments = array();
 
     $old_mask = array();
     $new_mask = array();
     $feedback_mask = array();
 
     if ($this->comments) {
       foreach ($this->comments as $comment) {
         $start = max($comment->getLineNumber() - self::LINES_CONTEXT, 0);
         $end = $comment->getLineNumber() +
                $comment->getLineLength() +
                self::LINES_CONTEXT;
         $new = $this->isCommentOnRightSideWhenDisplayed($comment);
         for ($ii = $start; $ii <= $end; $ii++) {
           if ($new) {
             $new_mask[$ii] = true;
           } else {
             $old_mask[$ii] = true;
           }
         }
       }
 
       foreach ($this->old as $ii => $old) {
         if (isset($old['line']) && isset($old_mask[$old['line']])) {
           $feedback_mask[$ii] = true;
         }
       }
 
       foreach ($this->new as $ii => $new) {
         if (isset($new['line']) && isset($new_mask[$new['line']])) {
           $feedback_mask[$ii] = true;
         }
       }
       $this->comments = msort($this->comments, 'getID');
       foreach ($this->comments as $comment) {
         $final = $comment->getLineNumber() +
                  $comment->getLineLength();
         if ($this->isCommentOnRightSideWhenDisplayed($comment)) {
           $new_comments[$final][] = $comment;
         } else {
           $old_comments[$final][] = $comment;
         }
       }
     }
 
     $html = $this->renderTextChange(
       $range_start,
       $range_len,
       $mask_force,
       $feedback_mask,
       $old_comments,
       $new_comments);
 
     return $this->renderChangesetTable($this->changeset, $html);
   }
 
   /**
    * Determine if an inline comment will appear on the rendered diff,
    * taking into consideration which halves of which changesets will actually
    * be shown.
    *
    * @param DifferentialInlineComment Comment to test for visibility.
    * @return bool True if the comment is visible on the rendered diff.
    */
   private function isCommentVisibleOnRenderedDiff(
     DifferentialInlineComment $comment) {
 
     $changeset_id = $comment->getChangesetID();
     $is_new = $comment->getIsNewFile();
 
     if ($changeset_id == $this->rightSideChangesetID &&
         $is_new == $this->rightSideAttachesToNewFile) {
       return true;
     }
 
     if ($changeset_id == $this->leftSideChangesetID &&
         $is_new == $this->leftSideAttachesToNewFile) {
       return true;
     }
 
     return false;
   }
 
 
   /**
    * Determine if a comment will appear on the right side of the display diff.
    * Note that the comment must appear somewhere on the rendered changeset, as
    * per isCommentVisibleOnRenderedDiff().
    *
    * @param DifferentialInlineComment Comment to test for display location.
    * @return bool True for right, false for left.
    */
   private function isCommentOnRightSideWhenDisplayed(
     DifferentialInlineComment $comment) {
 
     if (!$this->isCommentVisibleOnRenderedDiff($comment)) {
       throw new Exception("Comment is not visible on changeset!");
     }
 
     $changeset_id = $comment->getChangesetID();
     $is_new = $comment->getIsNewFile();
 
     if ($changeset_id == $this->rightSideChangesetID &&
         $is_new == $this->rightSideAttachesToNewFile) {
       return true;
     }
 
     return false;
   }
 
   protected function renderShield($message, $more) {
 
     if ($more) {
       $end = $this->getLength();
       $reference = $this->renderingReference;
       $more =
         ' '.
         javelin_render_tag(
           'a',
           array(
             'mustcapture' => true,
             'sigil'       => 'show-more',
             'class'       => 'complete',
             'href'        => '#',
             'meta'        => array(
               'ref'         => $reference,
               'range'       => "0-{$end}",
             ),
           ),
           'Show File Contents');
     } else {
       $more = null;
     }
 
     return javelin_render_tag(
       'tr',
       array(
         'sigil' => 'context-target',
       ),
       '<td class="differential-shield" colspan="4">'.
         phutil_escape_html($message).
         $more.
       '</td>');
   }
 
   protected function renderTextChange(
     $range_start,
     $range_len,
     $mask_force,
     $feedback_mask,
     array $old_comments,
     array $new_comments) {
 
     $context_not_available = null;
     if ($this->missingOld || $this->missingNew) {
       $context_not_available = javelin_render_tag(
         'tr',
         array(
           'sigil' => 'context-target',
         ),
         '<td colspan="4" class="show-more">'.
             'Context not available.'.
         '</td>');
       $context_not_available = $context_not_available;
     }
 
     $html = array();
 
     $rows = max(
       count($this->old),
       count($this->new));
 
     if ($range_start === null) {
       $range_start = 0;
     }
 
     if ($range_len === null) {
       $range_len = $rows;
     }
 
     $range_len = min($range_len, $rows - $range_start);
 
     // Gaps - compute gaps in the visible display diff, where we will render
     // "Show more context" spacers. This builds an aggregate $mask of all the
     // lines we must show (because they are near changed lines, near inline
     // comments, or the request has explicitly asked for them, i.e. resulting
     // from the user clicking "show more") and then finds all the gaps between
     // visible lines. If a gap is smaller than the context size, we just
     // display it. Otherwise, we record it into $gaps and will render a
     // "show more context" element instead of diff text below.
 
     $gaps = array();
     $gap_start = 0;
     $in_gap = false;
     $mask = $this->visible + $mask_force + $feedback_mask;
     $mask[$range_start + $range_len] = true;
     for ($ii = $range_start; $ii <= $range_start + $range_len; $ii++) {
       if (isset($mask[$ii])) {
         if ($in_gap) {
           $gap_length = $ii - $gap_start;
           if ($gap_length <= self::LINES_CONTEXT) {
             for ($jj = $gap_start; $jj <= $gap_start + $gap_length; $jj++) {
               $mask[$jj] = true;
             }
           } else {
             $gaps[] = array($gap_start, $gap_length);
           }
           $in_gap = false;
         }
       } else {
         if (!$in_gap) {
           $gap_start = $ii;
           $in_gap = true;
         }
       }
     }
 
     $gaps = array_reverse($gaps);
 
     $reference = $this->renderingReference;
 
     $left_id = $this->leftSideChangesetID;
     $right_id = $this->rightSideChangesetID;
 
     // "N" stands for 'new' and means the comment should attach to the new file
     // when stored, i.e. DifferentialInlineComment->setIsNewFile().
     // "O" stands for 'old' and means the comment should attach to the old file.
 
     $left_char = $this->leftSideAttachesToNewFile
       ? 'N'
       : 'O';
     $right_char = $this->rightSideAttachesToNewFile
       ? 'N'
       : 'O';
 
     for ($ii = $range_start; $ii < $range_start + $range_len; $ii++) {
       if (empty($mask[$ii])) {
         // If we aren't going to show this line, we've just entered a gap.
         // Pop information about the next gap off the $gaps stack and render
         // an appropriate "Show more context" element. This branch eventually
         // increments $ii by the entire size of the gap and then continues
         // the loop.
         $gap = array_pop($gaps);
         $top = $gap[0];
         $len = $gap[1];
 
         $end   = $top + $len - 20;
 
         $contents = array();
 
         if ($len > 40) {
           $contents[] = javelin_render_tag(
             'a',
             array(
               'href' => '#',
               'mustcapture' => true,
               'sigil'       => 'show-more',
               'meta'        => array(
                 'ref'    => $reference,
                 'range' => "{$top}-{$len}/{$top}-20",
               ),
             ),
             "\xE2\x96\xB2 Show 20 Lines");
         }
 
         $contents[] = javelin_render_tag(
           'a',
           array(
             'href' => '#',
             'mustcapture' => true,
             'sigil'       => 'show-more',
             'meta'        => array(
               'ref'    => $reference,
               'range' => "{$top}-{$len}/{$top}-{$len}",
             ),
           ),
           'Show All '.$len.' Lines');
 
         if ($len > 40) {
           $contents[] = javelin_render_tag(
             'a',
             array(
               'href' => '#',
               'mustcapture' => true,
               'sigil'       => 'show-more',
               'meta'        => array(
                 'ref'    => $reference,
                 'range' => "{$top}-{$len}/{$end}-20",
               ),
             ),
             "\xE2\x96\xBC Show 20 Lines");
         };
 
         $container = javelin_render_tag(
           'tr',
           array(
             'sigil' => 'context-target',
           ),
           '<td colspan="4" class="show-more">'.
             implode(' &bull; ', $contents).
           '</td>');
 
         $html[] = $container;
 
         $ii += ($len - 1);
         continue;
       }
 
       if (isset($this->old[$ii])) {
         $o_num  = $this->old[$ii]['line'];
         $o_text = isset($this->oldRender[$ii]) ? $this->oldRender[$ii] : null;
         $o_attr = null;
         if ($this->old[$ii]['type']) {
           if (empty($this->new[$ii])) {
             $o_attr = ' class="old old-full"';
           } else {
             $o_attr = ' class="old"';
           }
         }
       } else {
         $o_num  = null;
         $o_text = null;
         $o_attr = null;
       }
 
       if (isset($this->new[$ii])) {
         $n_num  = $this->new[$ii]['line'];
         $n_text = isset($this->newRender[$ii]) ? $this->newRender[$ii] : null;
         $n_attr = null;
         if ($this->new[$ii]['type']) {
           if (empty($this->old[$ii])) {
             $n_attr = ' class="new new-full"';
           } else {
             $n_attr = ' class="new"';
           }
         }
       } else {
         $n_num   = null;
         $n_text  = null;
         $n_attr  = null;
       }
 
 
       if (($o_num && !empty($this->missingOld[$o_num])) ||
           ($n_num && !empty($this->missingNew[$n_num]))) {
         $html[] = $context_not_available;
       }
 
       if ($o_num && $left_id) {
         $o_id = ' id="C'.$left_id.$left_char.'L'.$o_num.'"';
       } else {
         $o_id = null;
       }
 
       if ($n_num && $right_id) {
         $n_id = ' id="C'.$right_id.$right_char.'L'.$n_num.'"';
       } else {
         $n_id = null;
       }
 
       // NOTE: The Javascript is sensitive to whitespace changes in this
       // block!
       $html[] =
         '<tr>'.
           '<th'.$o_id.'>'.$o_num.'</th>'.
           '<td'.$o_attr.'>'.$o_text.'</td>'.
           '<th'.$n_id.'>'.$n_num.'</th>'.
           '<td'.$n_attr.'>'.$n_text.'</td>'.
         '</tr>';
 
       if ($context_not_available && ($ii == $rows - 1)) {
         $html[] = $context_not_available;
       }
 
       if ($o_num && isset($old_comments[$o_num])) {
         foreach ($old_comments[$o_num] as $comment) {
           $xhp = $this->renderInlineComment($comment);
           $html[] =
             '<tr class="inline"><th /><td>'.
               $xhp.
             '</td><th /><td /></tr>';
         }
       }
       if ($n_num && isset($new_comments[$n_num])) {
         foreach ($new_comments[$n_num] as $comment) {
           $xhp = $this->renderInlineComment($comment);
           $html[] =
             '<tr class="inline"><th /><td /><th /><td>'.
               $xhp.
             '</td></tr>';
         }
       }
     }
 
     return implode('', $html);
   }
 
   private function renderInlineComment(DifferentialInlineComment $comment) {
 
     $user = $this->user;
     $edit = $user &&
             ($comment->getAuthorPHID() == $user->getPHID()) &&
             (!$comment->getCommentID());
 
     $on_right = $this->isCommentOnRightSideWhenDisplayed($comment);
 
     return id(new DifferentialInlineCommentView())
       ->setInlineComment($comment)
       ->setOnRight($on_right)
       ->setHandles($this->handles)
       ->setMarkupEngine($this->markupEngine)
       ->setEditable($edit)
       ->render();
   }
 
   protected function renderPropertyChangeHeader($changeset) {
     if (!$this->isTopLevel) {
       // We render properties only at top level; otherwise we get multiple
       // copies of them when a user clicks "Show More".
       return null;
     }
 
     $old = $changeset->getOldProperties();
     $new = $changeset->getNewProperties();
 
     if ($old === $new) {
       return null;
     }
 
     if ($changeset->getChangeType() == DifferentialChangeType::TYPE_ADD &&
         $new == array('unix:filemode' => '100644')) {
       return null;
     }
 
     if ($changeset->getChangeType() == DifferentialChangeType::TYPE_DELETE &&
         $old == array('unix:filemode' => '100644')) {
       return null;
     }
 
     $keys = array_keys($old + $new);
     sort($keys);
 
     $rows = array();
     foreach ($keys as $key) {
       $oval = idx($old, $key);
       $nval = idx($new, $key);
       if ($oval !== $nval) {
         if ($oval === null) {
           $oval = '<em>null</em>';
         } else {
           $oval = phutil_escape_html($oval);
         }
 
         if ($nval === null) {
           $nval = '<em>null</em>';
         } else {
           $nval = phutil_escape_html($nval);
         }
 
         $rows[] =
           '<tr>'.
             '<th>'.phutil_escape_html($key).'</th>'.
             '<td class="oval">'.$oval.'</td>'.
             '<td class="nval">'.$nval.'</td>'.
           '</tr>';
       }
     }
 
     return
       '<table class="differential-property-table">'.
         '<tr class="property-table-header">'.
           '<th>Property Changes</th>'.
           '<td class="oval">Old Value</td>'.
           '<td class="nval">New Value</td>'.
         '</tr>'.
         implode('', $rows).
       '</table>';
   }
 
   protected function renderChangesetTable($changeset, $contents) {
     $props  = $this->renderPropertyChangeHeader($this->changeset);
     $table = null;
     if ($contents) {
       $table =
         '<table class="differential-diff remarkup-code PhabricatorMonospaced">'.
           $contents.
         '</table>';
     }
 
     if (!$table && !$props) {
       $notice = $this->renderChangeTypeHeader($this->changeset, true);
     } else {
       $notice = $this->renderChangeTypeHeader($this->changeset, false);
     }
 
     return implode(
       "\n",
       array(
         $notice,
         $props,
         $table,
       ));
   }
 
   protected function renderChangeTypeHeader($changeset, $force) {
 
     static $articles = array(
       DifferentialChangeType::FILE_IMAGE      => 'an',
     );
 
     static $files = array(
       DifferentialChangeType::FILE_TEXT       => 'file',
       DifferentialChangeType::FILE_IMAGE      => 'image',
       DifferentialChangeType::FILE_DIRECTORY  => 'directory',
       DifferentialChangeType::FILE_BINARY     => 'binary file',
       DifferentialChangeType::FILE_SYMLINK    => 'symlink',
     );
 
     static $changes = array(
       DifferentialChangeType::TYPE_ADD        => 'added',
       DifferentialChangeType::TYPE_CHANGE     => 'changed',
       DifferentialChangeType::TYPE_DELETE     => 'deleted',
       DifferentialChangeType::TYPE_MOVE_HERE  => 'moved from',
       DifferentialChangeType::TYPE_COPY_HERE  => 'copied from',
       DifferentialChangeType::TYPE_MOVE_AWAY  => 'moved to',
       DifferentialChangeType::TYPE_COPY_AWAY  => 'copied to',
       DifferentialChangeType::TYPE_MULTICOPY
         => 'deleted after being copied to',
     );
 
     $change = $changeset->getChangeType();
     $file = $changeset->getFileType();
 
     $message = null;
     if ($change == DifferentialChangeType::TYPE_CHANGE &&
         $file   == DifferentialChangeType::FILE_TEXT) {
       if ($force) {
         // We have to force something to render because there were no changes
         // of other kinds.
         $message = "This {$files[$file]} was not modified.";
       } else {
         // Default case of changes to a text file, no metadata.
         return null;
       }
     } else {
       $verb = idx($changes, $change, 'changed');
       switch ($change) {
         default:
           $message = "This {$files[$file]} was <strong>{$verb}</strong>.";
           break;
         case DifferentialChangeType::TYPE_MOVE_HERE:
         case DifferentialChangeType::TYPE_COPY_HERE:
           $message =
             "This {$files[$file]} was {$verb} ".
             "<strong>{$changeset->getOldFile()}</strong>.";
           break;
         case DifferentialChangeType::TYPE_MOVE_AWAY:
         case DifferentialChangeType::TYPE_COPY_AWAY:
         case DifferentialChangeType::TYPE_MULTICOPY:
           $paths = $changeset->getAwayPaths();
           if (count($paths) > 1) {
             $message =
               "This {$files[$file]} was {$verb}: ".
               "<strong>".implode(', ', $paths)."</strong>.";
           } else {
             $message =
               "This {$files[$file]} was {$verb} ".
               "<strong>".reset($paths)."</strong>.";
           }
           break;
         case DifferentialChangeType::TYPE_CHANGE:
           $message = "This is ".idx($articles, $file, 'a')." {$files[$file]}.";
           break;
       }
     }
 
     return
       '<div class="differential-meta-notice">'.
         $message.
       '</div>';
   }
 
   public function renderForEmail() {
     $ret = '';
 
     $min = min(count($this->old), count($this->new));
     for ($i = 0; $i < $min; $i++) {
       $o = $this->old[$i];
       $n = $this->new[$i];
 
       if (!isset($this->visible[$i])) {
         continue;
       }
 
       if ($o['line'] && $n['line']) {
         // It is quite possible there are better ways to achieve this. For
         // example, "white-space: pre;" can do a better job, WERE IT NOT for
         // broken email clients like OWA which use newlines to do weird
         // wrapping. So dont give them newlines.
         if (isset($this->intra[$i])) {
           $ret .= sprintf(
             "<font color=\"red\">-&nbsp;%s</font><br/>",
             str_replace(" ", "&nbsp;", phutil_escape_html($o['text']))
           );
           $ret .= sprintf(
             "<font color=\"green\">+&nbsp;%s</font><br/>",
             str_replace(" ", "&nbsp;", phutil_escape_html($n['text']))
           );
         } else {
           $ret .= sprintf("&nbsp;&nbsp;%s<br/>",
             str_replace(" ", "&nbsp;", phutil_escape_html($n['text']))
           );
         }
       } else if ($o['line'] && !$n['line']) {
         $ret .= sprintf(
           "<font color=\"red\">-&nbsp;%s</font><br/>",
           str_replace(" ", "&nbsp;", phutil_escape_html($o['text']))
         );
       } else {
         $ret .= sprintf(
           "<font color=\"green\">+&nbsp;%s</font><br/>",
           str_replace(" ", "&nbsp;", phutil_escape_html($n['text']))
         );
       }
     }
 
     return $ret;
   }
 
 }
diff --git a/src/applications/differential/parser/changeset/__init__.php b/src/applications/differential/parser/changeset/__init__.php
index 34285ac97..7ca3982ed 100644
--- a/src/applications/differential/parser/changeset/__init__.php
+++ b/src/applications/differential/parser/changeset/__init__.php
@@ -1,31 +1,30 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('arcanist', 'difference');
 phutil_require_module('arcanist', 'parser/diff');
 
 phutil_require_module('phabricator', 'applications/differential/constants/changetype');
 phutil_require_module('phabricator', 'applications/differential/storage/changeset');
 phutil_require_module('phabricator', 'applications/differential/storage/diff');
 phutil_require_module('phabricator', 'applications/differential/view/inlinecomment');
 phutil_require_module('phabricator', 'applications/files/uri');
-phutil_require_module('phabricator', 'infrastructure/env');
+phutil_require_module('phabricator', 'applications/markup/syntax');
 phutil_require_module('phabricator', 'infrastructure/javelin/markup');
 phutil_require_module('phabricator', 'storage/queryfx');
 
 phutil_require_module('phutil', 'error');
 phutil_require_module('phutil', 'filesystem');
 phutil_require_module('phutil', 'filesystem/tempfile');
 phutil_require_module('phutil', 'future');
 phutil_require_module('phutil', 'future/exec');
 phutil_require_module('phutil', 'markup');
-phutil_require_module('phutil', 'markup/syntax/engine/default');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('DifferentialChangesetParser.php');
diff --git a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
index 3bf7e7ee3..eac0ce27f 100644
--- a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
+++ b/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
@@ -1,371 +1,366 @@
 <?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 DiffusionBrowseFileController extends DiffusionController {
 
   protected $imageTypes = array(
     'png' => 'image/png',
     'gif' => 'image/gif',
     'ico' => 'image/png',
     'jpg' => 'image/jpeg',
     'jpeg'=> 'image/jpeg'
   );
 
 
   public function processRequest() {
 
     // Build the view selection form.
     $select_map = array(
       'highlighted' => 'View as Highlighted Text',
       'blame' => 'View as Highlighted Text with Blame',
       'plain' => 'View as Plain Text',
       'plainblame' => 'View as Plain Text with Blame',
     );
 
     $request = $this->getRequest();
 
     $selected = $request->getStr('view');
     $select = '<select name="view">';
     foreach ($select_map as $k => $v) {
       $option = phutil_render_tag(
         'option',
         array(
           'value' => $k,
           'selected' => ($k == $selected) ? 'selected' : null,
         ),
         phutil_escape_html($v));
 
       $select .= $option;
     }
     $select .= '</select>';
 
     require_celerity_resource('diffusion-source-css');
 
     $view_select_panel = new AphrontPanelView();
     $view_select_form = phutil_render_tag(
       'form',
       array(
         'action' => $request->getRequestURI(),
         'method' => 'get',
         'class'  => 'diffusion-browse-type-form',
       ),
       $select.
       '<button>View</button>');
     $view_select_panel->appendChild($view_select_form);
     $view_select_panel->appendChild('<div style="clear: both;"></div>');
 
     // Build the content of the file.
     $corpus = $this->buildCorpus($selected);
 
     // Render the page.
     $content = array();
     $content[] = $this->buildCrumbs(
       array(
         'branch' => true,
         'path'   => true,
         'view'   => 'browse',
       ));
     $content[] = $view_select_panel;
     $content[] = $corpus;
 
     $nav = $this->buildSideNav('browse', true);
     $nav->appendChild($content);
 
     $basename = basename($this->getDiffusionRequest()->getPath());
 
     return $this->buildStandardPageResponse(
       $nav,
       array(
         'title' => $basename,
       ));
   }
 
 
   /*
    * Returns a content-type corrsponding to an image file extension
    *
    * @param string $path File path
    * @return mixed A content-type string or NULL if path doesn't end with a
    *               recognized image extension
    */
   public function getImageType($path) {
     $ext = pathinfo($path);
     $ext = idx($ext, 'extension');
     return idx($this->imageTypes, $ext);
   }
 
 
   private function buildCorpus($selected) {
     $needs_blame = ($selected == 'blame' || $selected == 'plainblame');
 
     $file_query = DiffusionFileContentQuery::newFromDiffusionRequest(
       $this->diffusionRequest);
     $file_query->setNeedsBlame($needs_blame);
     $file_query->loadFileContent();
 
     $drequest = $this->getDiffusionRequest();
     $path = $drequest->getPath();
 
     $image_type = $this->getImageType($path);
     if ($image_type && !$selected) {
       $data = $file_query->getRawData();
 
       $corpus = phutil_render_tag(
         'img',
         array(
           'style' => 'padding-bottom: 10px',
           'src' => 'data:'.$image_type.';base64,'.base64_encode($data),
         )
       );
       return $corpus;
     }
 
     // TODO: blame of blame.
     switch ($selected) {
       case 'plain':
         $style =
           "margin: 1em 2em; width: 90%; height: 80em; font-family: monospace";
         $corpus = phutil_render_tag(
           'textarea',
           array(
             'style' => $style,
           ),
           phutil_escape_html($file_query->getRawData()));
 
           break;
 
       case 'plainblame':
         $style =
           "margin: 1em 2em; width: 90%; height: 80em; font-family: monospace";
         list($text_list, $rev_list, $blame_dict) =
           $file_query->getBlameData();
 
         $rows = array();
         foreach ($text_list as $k => $line) {
           $rev = $rev_list[$k];
           $author = $blame_dict[$rev]['author'];
           $rows[] =
             sprintf("%-10s %-20s %s", substr($rev, 0, 7), $author, $line);
         }
 
         $corpus = phutil_render_tag(
           'textarea',
           array(
             'style' => $style,
           ),
           phutil_escape_html(implode("\n", $rows)));
 
         break;
 
       case 'highlighted':
       case 'blame':
       default:
         require_celerity_resource('syntax-highlighting-css');
 
         list($text_list, $rev_list, $blame_dict) = $file_query->getBlameData();
 
-        $highlight_engine = new PhutilDefaultSyntaxHighlighterEngine();
-        $highlight_engine->setConfig(
-          'pygments.enabled',
-          PhabricatorEnv::getEnvConfig('pygments.enabled'));
-
-        $text_list = explode(
-          "\n",
-          $highlight_engine->highlightSource(
-            $highlight_engine->getLanguageFromFilename($path),
-            implode("\n", $text_list)));
+        $text_list = implode("\n", $text_list);
+        $text_list = PhabricatorSyntaxHighlighter::highlightWithFilename(
+          $path,
+          $text_list);
+        $text_list = explode("\n", $text_list);
 
         $rows = $this->buildDisplayRows($text_list, $rev_list, $blame_dict,
           $needs_blame, $drequest, $file_query, $selected);
 
         $corpus_table = phutil_render_tag(
           'table',
           array(
             'class' => "diffusion-source remarkup-code PhabricatorMonospaced",
           ),
           implode("\n", $rows));
         $corpus = phutil_render_tag(
           'div',
           array(
             'style' => 'padding: 0pt 2em;',
           ),
           $corpus_table);
 
         break;
     }
 
     return $corpus;
   }
 
 
   private function buildDisplayRows($text_list, $rev_list, $blame_dict,
     $needs_blame, DiffusionRequest $drequest, $file_query, $selected) {
     $last_rev = null;
     $color = null;
     $rows = array();
     $n = 1;
     $view = $this->getRequest()->getStr('view');
 
     if ($blame_dict) {
       $epoch_list = ipull($blame_dict, 'epoch');
       $max = max($epoch_list);
       $min = min($epoch_list);
       $range = $max - $min + 1;
     } else {
       $range = 1;
     }
 
     foreach ($text_list as $k => $line) {
       if ($needs_blame) {
         // If the line's rev is same as the line above, show empty content
         // with same color; otherwise generate blame info. The newer a change
         // is, the darker the color.
         $rev = $rev_list[$k];
         if ($last_rev == $rev) {
           $blame_info =
             ($file_query->getSupportsBlameOnBlame() ?
               '<th style="background: '.$color.'; width: 2em;"></th>' : '').
             '<th style="background: '.$color.'; width: 9em;"></th>'.
             '<th style="background: '.$color.'"></th>';
         } else {
 
           $color_number = (int)(0xEE -
             0xEE * ($blame_dict[$rev]['epoch'] - $min) / $range);
           $color = sprintf('#%02xee%02x', $color_number, $color_number);
 
           $revision_link = self::renderRevision(
             $drequest,
             substr($rev, 0, 7));
 
           if (!$file_query->getSupportsBlameOnBlame()) {
             $prev_link = '';
           } else {
             $prev_rev = $file_query->getPrevRev($rev);
             $path = $drequest->getPath();
             $prev_link = self::renderBrowse(
               $drequest,
               $path,
               "\xC2\xAB",
               $prev_rev,
               $n,
               $selected);
             $prev_link = '<th style="background: ' . $color .
               '; width: 2em;">' . $prev_link . '</th>';
           }
 
           $author_link = $blame_dict[$rev]['author'];
           $blame_info =
             $prev_link .
             '<th style="background: '.$color.
               '; width: 12em;">'.$revision_link.'</th>'.
             '<th style="background: '.$color.'; width: 12em'.
               '; font-weight: normal; color: #333;">'.$author_link.'</th>';
           $last_rev = $rev;
         }
       } else {
         $blame_info = null;
       }
 
       // Highlight the line of interest if needed.
       if ($n == $drequest->getLine()) {
         $tr = '<tr style="background: #ffff00;">';
         $targ = '<a id="scroll_target"></a>';
         Javelin::initBehavior('diffusion-jump-to',
           array('target' => 'scroll_target'));
       } else {
         $tr = '<tr>';
         $targ = null;
       }
 
       // Create the row display.
       $uri_path = $drequest->getUriPath();
       $uri_rev  = $drequest->getStableCommitName();
       $uri_view = $view
         ? '?view='.$view
         : null;
 
       $l = phutil_render_tag(
         'a',
         array(
           'class' => 'diffusion-line-link',
           'href' => $uri_path.';'.$uri_rev.'$'.$n.$uri_view,
         ),
         $n);
 
       $rows[] = $tr.$blame_info.'<th>'.$l.'</th><td>'.$targ.$line.'</td></tr>';
       ++$n;
     }
 
     return $rows;
   }
 
 
   private static function renderRevision(DiffusionRequest $drequest,
     $revision) {
 
     $callsign = $drequest->getCallsign();
 
     $name = 'r'.$callsign.$revision;
     return phutil_render_tag(
       'a',
       array(
            'href' => '/'.$name,
       ),
       $name
     );
   }
 
 
   private static function renderBrowse(
     DiffusionRequest $drequest,
     $path,
     $name = null,
     $rev = null,
     $line = null,
     $view = null) {
 
     $callsign = $drequest->getCallsign();
 
     if ($name === null) {
       $name = $path;
     }
 
     $at = null;
     if ($rev) {
       $at = ';'.$rev;
     }
 
     if ($view) {
       $view = '?view='.$view;
     }
 
     if ($line) {
       $line = '$'.$line;
     }
 
     return phutil_render_tag(
       'a',
       array(
         'href' => "/diffusion/{$callsign}/browse/{$path}{$at}{$line}{$view}",
       ),
       $name
     );
   }
 
 
 }
diff --git a/src/applications/diffusion/controller/file/__init__.php b/src/applications/diffusion/controller/file/__init__.php
index 8b61c7396..7bba4cebc 100644
--- a/src/applications/diffusion/controller/file/__init__.php
+++ b/src/applications/diffusion/controller/file/__init__.php
@@ -1,21 +1,20 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/diffusion/controller/base');
 phutil_require_module('phabricator', 'applications/diffusion/query/filecontent/base');
+phutil_require_module('phabricator', 'applications/markup/syntax');
 phutil_require_module('phabricator', 'infrastructure/celerity/api');
-phutil_require_module('phabricator', 'infrastructure/env');
 phutil_require_module('phabricator', 'infrastructure/javelin/api');
 phutil_require_module('phabricator', 'view/layout/panel');
 
 phutil_require_module('phutil', 'markup');
-phutil_require_module('phutil', 'markup/syntax/engine/default');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('DiffusionBrowseFileController.php');
diff --git a/src/applications/markup/syntax/PhabricatorSyntaxHighlighter.php b/src/applications/markup/syntax/PhabricatorSyntaxHighlighter.php
new file mode 100644
index 000000000..52597ec33
--- /dev/null
+++ b/src/applications/markup/syntax/PhabricatorSyntaxHighlighter.php
@@ -0,0 +1,51 @@
+<?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.
+ */
+
+/**
+ * @group markup
+ */
+final class PhabricatorSyntaxHighlighter {
+
+  public static function newEngine() {
+    $engine = new PhutilDefaultSyntaxHighlighterEngine();
+
+    $config = array(
+      'pygments.enabled' => PhabricatorEnv::getEnvConfig('pygments.enabled'),
+      'filename.map'     => PhabricatorEnv::getEnvConfig('syntax.filemap'),
+    );
+
+    foreach ($config as $key => $value) {
+      $engine->setConfig($key, $value);
+    }
+
+    return $engine;
+  }
+
+  public static function highlightWithFilename($filename, $source) {
+    $engine = self::newEngine();
+    $language = $engine->getLanguageFromFilename($filename);
+    return $engine->getHighlightFuture($language, $source)->resolve();
+  }
+
+  public static function highlightWithLanguage($language, $source) {
+    $engine = self::newEngine();
+    return $engine->getHighlightFuture($language, $source)->resolve();
+  }
+
+
+}
diff --git a/src/applications/markup/syntax/__init__.php b/src/applications/markup/syntax/__init__.php
new file mode 100644
index 000000000..230b375ab
--- /dev/null
+++ b/src/applications/markup/syntax/__init__.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'infrastructure/env');
+
+phutil_require_module('phutil', 'markup/syntax/engine/default');
+
+
+phutil_require_source('PhabricatorSyntaxHighlighter.php');
diff --git a/src/applications/paste/controller/view/PhabricatorPasteViewController.php b/src/applications/paste/controller/view/PhabricatorPasteViewController.php
index 280939585..90816f9de 100644
--- a/src/applications/paste/controller/view/PhabricatorPasteViewController.php
+++ b/src/applications/paste/controller/view/PhabricatorPasteViewController.php
@@ -1,146 +1,142 @@
 <?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 PhabricatorPasteViewController extends PhabricatorPasteController {
 
   private $id;
 
   public function willProcessRequest(array $data) {
     $this->id = $data['id'];
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
     $user = $request->getUser();
 
     $paste = id(new PhabricatorPaste())->load($this->id);
     if (!$paste) {
       return new Aphront404Response();
     }
 
     $file = id(new PhabricatorFile())->loadOneWhere(
       'phid = %s',
       $paste->getFilePHID());
     if (!$file) {
       return new Aphront400Response();
     }
 
     $corpus = $this->buildCorpus($paste, $file);
 
     $panel = new AphrontPanelView();
 
     if (strlen($paste->getTitle())) {
       $panel->setHeader(
         'Viewing Paste '.$paste->getID().' - '.
         phutil_escape_html($paste->getTitle()));
     } else {
       $panel->setHeader('Viewing Paste '.$paste->getID());
     }
 
     $panel->setWidth(AphrontPanelView::WIDTH_FULL);
     $panel->addButton(
       phutil_render_tag(
         'a',
         array(
           'href' => '/paste/?copy='.$paste->getID(),
           'class' => 'green button',
         ),
         'Copy This'));
 
     $raw_uri = PhabricatorFileURI::getViewURIForPHID($paste->getFilePHID());
     $panel->addButton(
       phutil_render_tag(
         'a',
         array(
           'href'  => $raw_uri,
           'class' => 'button',
         ),
         'View Raw Text'));
 
     $panel->appendChild($corpus);
 
     return $this->buildStandardPageResponse(
       $panel,
       array(
         'title' => 'Paste: '.nonempty($paste->getTitle(), 'P'.$paste->getID()),
         'tab' => 'view',
       ));
   }
 
   private function buildCorpus($paste, $file) {
     // Blantently copied from DiffusionBrowseFileController
 
     require_celerity_resource('diffusion-source-css');
     require_celerity_resource('syntax-highlighting-css');
 
-    $highlight_engine = new PhutilDefaultSyntaxHighlighterEngine();
-    $highlight_engine->setConfig(
-      'pygments.enabled',
-      PhabricatorEnv::getEnvConfig('pygments.enabled'));
-
-
     $language = $paste->getLanguage();
+    $source = $file->loadFileData();
     if (empty($language)) {
-      $language = $highlight_engine->getLanguageFromFilename(
-        $paste->getTitle());
+      $source = PhabricatorSyntaxHighlighter::highlightWithFilename(
+        $paste->getTitle(),
+        $source);
+    } else {
+      $source = PhabricatorSyntaxHighlighter::highlightWithLanguage(
+        $language,
+        $source);
     }
 
-    $text_list = explode(
-      "\n",
-      $highlight_engine->highlightSource(
-        $language,
-        $file->loadFileData()));
+    $text_list = explode("\n", $source);
 
     $rows = $this->buildDisplayRows($text_list);
 
     $corpus_table = phutil_render_tag(
       'table',
       array(
         'class' => 'diffusion-source remarkup-code PhabricatorMonospaced',
       ),
       implode("\n", $rows));
 
     $corpus = phutil_render_tag(
       'div',
       array(
         'style' => 'padding: 0pt 2em;',
       ),
       $corpus_table);
 
     return $corpus;
   }
 
   private function buildDisplayRows($text_list) {
     $rows = array();
     $n = 1;
 
     foreach ($text_list as $k => $line) {
       // Pardon the ugly for the time being.
       // And eventually this will highlight a line that you click
       // like diffusion does. Or maybe allow for line comments
       // like differential. Either way it will be better than it is now.
       $rows[] = '<tr><th>'.$n.'</th>'.
         '<td style="white-space: pre-wrap;">'.$line.'</td></tr>';
       ++$n;
     }
 
     return $rows;
   }
 
 }
diff --git a/src/applications/paste/controller/view/__init__.php b/src/applications/paste/controller/view/__init__.php
index fc6f4b854..527fc99e5 100644
--- a/src/applications/paste/controller/view/__init__.php
+++ b/src/applications/paste/controller/view/__init__.php
@@ -1,24 +1,23 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'aphront/response/400');
 phutil_require_module('phabricator', 'aphront/response/404');
 phutil_require_module('phabricator', 'applications/files/storage/file');
 phutil_require_module('phabricator', 'applications/files/uri');
+phutil_require_module('phabricator', 'applications/markup/syntax');
 phutil_require_module('phabricator', 'applications/paste/controller/base');
 phutil_require_module('phabricator', 'applications/paste/storage/paste');
 phutil_require_module('phabricator', 'infrastructure/celerity/api');
-phutil_require_module('phabricator', 'infrastructure/env');
 phutil_require_module('phabricator', 'view/layout/panel');
 
 phutil_require_module('phutil', 'markup');
-phutil_require_module('phutil', 'markup/syntax/engine/default');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhabricatorPasteViewController.php');