diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index dde6623a43..5c91811317 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,1779 +1,1782 @@
 <?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',
     'Aphront403Response' => 'aphront/response/403',
     'Aphront404Response' => 'aphront/response/404',
     'AphrontAjaxResponse' => 'aphront/response/ajax',
     'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
     'AphrontAttachedFileView' => 'view/control/attachedfile',
     'AphrontCSRFException' => 'aphront/exception/csrf',
     'AphrontCalendarMonthView' => 'applications/calendar/view/month',
     'AphrontContextBarView' => 'view/layout/contextbar',
     'AphrontController' => 'aphront/controller',
     'AphrontCrumbsView' => 'view/layout/crumbs',
     'AphrontDatabaseConnection' => 'storage/connection/base',
     'AphrontDatabaseTransactionState' => 'storage/transaction',
     'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
     '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',
     'AphrontFormDateControl' => 'view/form/control/date',
     'AphrontFormDividerControl' => 'view/form/control/divider',
     'AphrontFormDragAndDropUploadControl' => 'view/form/control/draganddropupload',
     'AphrontFormFileControl' => 'view/form/control/file',
     'AphrontFormInsetView' => 'view/form/inset',
     'AphrontFormLayoutView' => 'view/form/layout',
     'AphrontFormMarkupControl' => 'view/form/control/markup',
     'AphrontFormPasswordControl' => 'view/form/control/password',
     'AphrontFormRadioButtonControl' => 'view/form/control/radio',
     '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',
     'AphrontHTTPSink' => 'aphront/sink/base',
     'AphrontHTTPSinkTestCase' => 'aphront/sink/base/__tests__',
     'AphrontHeadsupActionListView' => 'view/layout/headsup/actionlist',
     'AphrontHeadsupActionView' => 'view/layout/headsup/action',
     'AphrontHeadsupView' => 'view/layout/headsup/panel',
     'AphrontIsolatedDatabaseConnection' => 'storage/connection/isolated',
     'AphrontIsolatedDatabaseConnectionTestCase' => 'storage/connection/isolated/__tests__',
     'AphrontIsolatedHTTPSink' => 'aphront/sink/test',
     'AphrontJSONResponse' => 'aphront/response/json',
     'AphrontJavelinView' => 'view/javelin-view',
     'AphrontKeyboardShortcutsAvailableView' => 'view/widget/keyboardshortcuts',
     'AphrontListFilterView' => 'view/layout/listfilter',
     'AphrontMiniPanelView' => 'view/layout/minipanel',
     'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql/mysql',
     'AphrontMySQLDatabaseConnectionBase' => 'storage/connection/mysql/base',
     'AphrontMySQLDatabaseConnectionTestCase' => 'storage/connection/mysql/__tests__',
     'AphrontMySQLiDatabaseConnection' => 'storage/connection/mysql/mysqli',
     'AphrontNullView' => 'view/null',
     'AphrontPHPHTTPSink' => 'aphront/sink/php',
     'AphrontPageView' => 'view/page/base',
     'AphrontPagerView' => 'view/control/pager',
     'AphrontPanelView' => 'view/layout/panel',
     'AphrontPlainTextResponse' => 'aphront/response/plaintext',
     'AphrontProxyResponse' => 'aphront/response/proxy',
     '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',
     'AphrontQuerySchemaException' => 'storage/exception/schema',
     'AphrontRedirectException' => 'aphront/exception/redirect',
     'AphrontRedirectResponse' => 'aphront/response/redirect',
     'AphrontReloadResponse' => 'aphront/response/reload',
     'AphrontRequest' => 'aphront/request',
     'AphrontRequestFailureView' => 'view/page/failure',
     'AphrontRequestTestCase' => 'aphront/request/__tests__',
     'AphrontResponse' => 'aphront/response/base',
     'AphrontScopedUnguardedWriteCapability' => 'aphront/writeguard/scopeguard',
     'AphrontSideNavFilterView' => 'view/layout/sidenavfilter',
     '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',
     'AphrontWriteGuard' => 'aphront/writeguard',
     'CelerityAPI' => 'infrastructure/celerity/api',
     'CelerityResourceController' => 'infrastructure/celerity/controller',
     'CelerityResourceGraph' => 'infrastructure/celerity/graph',
     'CelerityResourceMap' => 'infrastructure/celerity/map',
     'CelerityResourceTransformer' => 'infrastructure/celerity/transformer',
     'CelerityResourceTransformerTestCase' => 'infrastructure/celerity/transformer/__tests__',
     'CelerityStaticResourceResponse' => 'infrastructure/celerity/response',
     'ConduitAPIMethod' => 'applications/conduit/method/base',
     'ConduitAPIRequest' => 'applications/conduit/protocol/request',
     'ConduitAPIResponse' => 'applications/conduit/protocol/response',
     'ConduitAPI_arcanist_Method' => 'applications/conduit/method/arcanist/base',
     'ConduitAPI_arcanist_projectinfo_Method' => 'applications/conduit/method/arcanist/projectinfo',
     'ConduitAPI_audit_Method' => 'applications/conduit/method/audit/base',
     'ConduitAPI_audit_query_Method' => 'applications/conduit/method/audit/query',
     'ConduitAPI_chatlog_Method' => 'applications/conduit/method/chatlog/base',
     'ConduitAPI_chatlog_query_Method' => 'applications/conduit/method/chatlog/query',
     'ConduitAPI_chatlog_record_Method' => 'applications/conduit/method/chatlog/record',
     '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_createcomment_Method' => 'applications/conduit/method/differential/createcomment',
     '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_getrevisioncomments_Method' => 'applications/conduit/method/differential/getrevisioncomments',
     '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_query_Method' => 'applications/conduit/method/differential/query',
     '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_findsymbols_Method' => 'applications/conduit/method/diffusion/findsymbols',
     'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits',
     'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/conduit/method/diffusion/getrecentcommitsbypath',
     'ConduitAPI_feed_publish_Method' => 'applications/conduit/method/feed/publish',
     'ConduitAPI_feed_query_Method' => 'applications/conduit/method/feed/query',
     'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download',
     'ConduitAPI_file_info_Method' => 'applications/conduit/method/file/info',
     'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
     'ConduitAPI_flag_Method' => 'applications/conduit/method/flag/base',
     'ConduitAPI_flag_query_Method' => 'applications/conduit/method/flag/query',
     'ConduitAPI_macro_Method' => 'applications/conduit/method/macro/base',
     'ConduitAPI_macro_query_Method' => 'applications/conduit/method/macro/query',
     'ConduitAPI_maniphest_Method' => 'applications/conduit/method/maniphest/base',
     'ConduitAPI_maniphest_createtask_Method' => 'applications/conduit/method/maniphest/createtask',
     'ConduitAPI_maniphest_find_Method' => 'applications/conduit/method/maniphest/find',
     'ConduitAPI_maniphest_gettasktransactions_Method' => 'applications/conduit/method/maniphest/gettasktransactions',
     'ConduitAPI_maniphest_info_Method' => 'applications/conduit/method/maniphest/info',
     'ConduitAPI_maniphest_update_Method' => 'applications/conduit/method/maniphest/update',
     'ConduitAPI_paste_Method' => 'applications/conduit/method/paste/base',
     'ConduitAPI_paste_create_Method' => 'applications/conduit/method/paste/create',
     'ConduitAPI_paste_info_Method' => 'applications/conduit/method/paste/info',
     'ConduitAPI_path_getowners_Method' => 'applications/conduit/method/path/getowners',
     'ConduitAPI_phid_Method' => 'applications/conduit/method/phid/base',
     'ConduitAPI_phid_info_Method' => 'applications/conduit/method/phid/info',
     'ConduitAPI_phid_query_Method' => 'applications/conduit/method/phid/query',
     'ConduitAPI_phriction_Method' => 'applications/conduit/method/phriction/base',
     'ConduitAPI_phriction_edit_Method' => 'applications/conduit/method/phriction/edit',
     'ConduitAPI_phriction_history_Method' => 'applications/conduit/method/phriction/history',
     'ConduitAPI_phriction_info_Method' => 'applications/conduit/method/phriction/info',
     'ConduitAPI_project_Method' => 'applications/conduit/method/project/base',
     'ConduitAPI_project_query_Method' => 'applications/conduit/method/project/query',
     'ConduitAPI_remarkup_process_Method' => 'applications/conduit/method/remarkup/process',
     'ConduitAPI_slowvote_info_Method' => 'applications/conduit/method/slowvote/info',
     'ConduitAPI_user_Method' => 'applications/conduit/method/user/base',
     'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
     'ConduitAPI_user_info_Method' => 'applications/conduit/method/user/info',
     'ConduitAPI_user_whoami_Method' => 'applications/conduit/method/user/whoami',
     'ConduitException' => 'applications/conduit/protocol/exception',
     'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
     'DarkConsoleController' => 'aphront/console/controller',
     'DarkConsoleCore' => 'aphront/console/core',
     'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog',
     'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api',
     'DarkConsoleEventPlugin' => 'aphront/console/plugin/event',
     'DarkConsoleEventPluginAPI' => 'aphront/console/plugin/event/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/base',
     'DefaultDatabaseConfigurationProvider' => 'applications/base/storage/configuration/default',
     'DifferentialAction' => 'applications/differential/constants/action',
     'DifferentialActionHasNoEffectException' => 'applications/differential/exception/noeffect',
     'DifferentialAddCommentView' => 'applications/differential/view/addcomment',
     'DifferentialAffectedPath' => 'applications/differential/storage/affectedpath',
     'DifferentialApplyPatchFieldSpecification' => 'applications/differential/field/specification/applypatch',
     'DifferentialArcanistProjectFieldSpecification' => 'applications/differential/field/specification/arcanistproject',
     'DifferentialAuditorsFieldSpecification' => 'applications/differential/field/specification/auditors',
     'DifferentialAuthorFieldSpecification' => 'applications/differential/field/specification/author',
     'DifferentialAuxiliaryField' => 'applications/differential/storage/auxiliaryfield',
     'DifferentialBlameRevisionFieldSpecification' => 'applications/differential/field/specification/blamerev',
     'DifferentialBranchFieldSpecification' => 'applications/differential/field/specification/branch',
     'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
     'DifferentialCCsFieldSpecification' => 'applications/differential/field/specification/ccs',
     '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',
     'DifferentialCommitsFieldSpecification' => 'applications/differential/field/specification/commits',
     'DifferentialController' => 'applications/differential/controller/base',
     'DifferentialDAO' => 'applications/differential/storage/base',
     'DifferentialDateCreatedFieldSpecification' => 'applications/differential/field/specification/datecreated',
     'DifferentialDateModifiedFieldSpecification' => 'applications/differential/field/specification/datemodified',
     'DifferentialDefaultFieldSelector' => 'applications/differential/field/selector/default',
     'DifferentialDependenciesFieldSpecification' => 'applications/differential/field/specification/dependencies',
     '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',
     'DifferentialException' => 'applications/differential/exception/base',
     'DifferentialExceptionMail' => 'applications/differential/mail/exception',
     'DifferentialExportPatchFieldSpecification' => 'applications/differential/field/specification/exportpatch',
     'DifferentialFieldDataNotAvailableException' => 'applications/differential/field/exception/notavailable',
     'DifferentialFieldParseException' => 'applications/differential/field/exception/parse',
     'DifferentialFieldSelector' => 'applications/differential/field/selector/base',
     'DifferentialFieldSpecification' => 'applications/differential/field/specification/base',
     'DifferentialFieldSpecificationIncompleteException' => 'applications/differential/field/exception/incomplete',
     'DifferentialFieldValidationException' => 'applications/differential/field/exception/validation',
     'DifferentialGitSVNIDFieldSpecification' => 'applications/differential/field/specification/gitsvnid',
     'DifferentialHostFieldSpecification' => 'applications/differential/field/specification/host',
     'DifferentialHunk' => 'applications/differential/storage/hunk',
     'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment',
     'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit',
     'DifferentialInlineCommentEditView' => 'applications/differential/view/inlinecommentedit',
     'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview',
     'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment',
     'DifferentialLinesFieldSpecification' => 'applications/differential/field/specification/lines',
     'DifferentialLintFieldSpecification' => 'applications/differential/field/specification/lint',
     'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
     'DifferentialLocalCommitsView' => 'applications/differential/view/localcommits',
     'DifferentialMail' => 'applications/differential/mail/base',
     'DifferentialManiphestTasksFieldSpecification' => 'applications/differential/field/specification/maniphesttasks',
     'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff',
     'DifferentialPathFieldSpecification' => 'applications/differential/field/specification/path',
     'DifferentialPrimaryPaneView' => 'applications/differential/view/primarypane',
     'DifferentialReplyHandler' => 'applications/differential/replyhandler',
     'DifferentialRevertPlanFieldSpecification' => 'applications/differential/field/specification/revertplan',
     'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
     'DifferentialReviewedByFieldSpecification' => 'applications/differential/field/specification/reviewedby',
     'DifferentialReviewersFieldSpecification' => 'applications/differential/field/specification/reviewers',
     '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',
     'DifferentialRevisionIDFieldParserTestCase' => 'applications/differential/field/specification/revisionid/__tests__',
     'DifferentialRevisionIDFieldSpecification' => 'applications/differential/field/specification/revisionid',
     'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
     'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
     'DifferentialRevisionListView' => 'applications/differential/view/revisionlist',
     'DifferentialRevisionQuery' => 'applications/differential/query/revision',
     'DifferentialRevisionStatsController' => 'applications/differential/controller/revisionstats',
     'DifferentialRevisionStatsView' => 'applications/differential/view/revisionstats',
     'DifferentialRevisionStatusFieldSpecification' => 'applications/differential/field/specification/revisionstatus',
     'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
     'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
     'DifferentialSubscribeController' => 'applications/differential/controller/subscribe',
     'DifferentialSummaryFieldSpecification' => 'applications/differential/field/specification/summary',
     'DifferentialTasksAttacher' => 'applications/differential/tasks',
     'DifferentialTestPlanFieldSpecification' => 'applications/differential/field/specification/testplan',
     'DifferentialTitleFieldSpecification' => 'applications/differential/field/specification/title',
     'DifferentialUnitFieldSpecification' => 'applications/differential/field/specification/unit',
     'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
     'DifferentialUnitTestResult' => 'applications/differential/constants/unittestresult',
     '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',
     'DiffusionCommentListView' => 'applications/diffusion/view/commentlist',
     'DiffusionCommentView' => 'applications/diffusion/view/comment',
     'DiffusionCommitChangeTableView' => 'applications/diffusion/view/commitchangetable',
     'DiffusionCommitController' => 'applications/diffusion/controller/commit',
     'DiffusionCommitParentsQuery' => 'applications/diffusion/query/parents/base',
     'DiffusionContainsQuery' => 'applications/diffusion/query/contains/base',
     'DiffusionController' => 'applications/diffusion/controller/base',
     'DiffusionDiffController' => 'applications/diffusion/controller/diff',
     'DiffusionDiffQuery' => 'applications/diffusion/query/diff/base',
     'DiffusionEmptyResultView' => 'applications/diffusion/view/emptyresult',
     'DiffusionExternalController' => 'applications/diffusion/controller/external',
     'DiffusionFileContent' => 'applications/diffusion/data/filecontent',
     'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base',
     'DiffusionGitBranchQuery' => 'applications/diffusion/query/branch/git',
     'DiffusionGitBranchQueryTestCase' => 'applications/diffusion/query/branch/git/__tests__',
     'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git',
     'DiffusionGitCommitParentsQuery' => 'applications/diffusion/query/parents/git',
     'DiffusionGitContainsQuery' => 'applications/diffusion/query/contains/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',
     'DiffusionGitMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/git',
     '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',
     'DiffusionInlineCommentController' => 'applications/diffusion/controller/inline',
     'DiffusionLastModifiedController' => 'applications/diffusion/controller/lastmodified',
     'DiffusionLastModifiedQuery' => 'applications/diffusion/query/lastmodified/base',
     'DiffusionMercurialBranchQuery' => 'applications/diffusion/query/branch/mercurial',
     'DiffusionMercurialBrowseQuery' => 'applications/diffusion/query/browse/mercurial',
     'DiffusionMercurialCommitParentsQuery' => 'applications/diffusion/query/parents/mercurial',
     'DiffusionMercurialContainsQuery' => 'applications/diffusion/query/contains/mercurial',
     'DiffusionMercurialDiffQuery' => 'applications/diffusion/query/diff/mercurial',
     'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/mercurial',
     'DiffusionMercurialHistoryQuery' => 'applications/diffusion/query/history/mercurial',
     'DiffusionMercurialLastModifiedQuery' => 'applications/diffusion/query/lastmodified/mercurial',
     'DiffusionMercurialMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/mercurial',
     'DiffusionMercurialRequest' => 'applications/diffusion/request/mercurial',
     'DiffusionMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/base',
     'DiffusionPathChange' => 'applications/diffusion/data/pathchange',
     'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/base',
     'DiffusionPathCompleteController' => 'applications/diffusion/controller/pathcomplete',
     'DiffusionPathIDQuery' => 'applications/diffusion/query/pathid/base',
     'DiffusionPathQuery' => 'applications/diffusion/query/path',
     'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/base/__tests__',
     'DiffusionPathValidateController' => 'applications/diffusion/controller/pathvalidate',
     'DiffusionQuery' => 'applications/diffusion/query/base',
     'DiffusionRepositoryController' => 'applications/diffusion/controller/repository',
     'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath',
     'DiffusionRequest' => 'applications/diffusion/request/base',
     'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/svn',
     'DiffusionSvnCommitParentsQuery' => 'applications/diffusion/query/parents/svn',
     'DiffusionSvnContainsQuery' => 'applications/diffusion/query/contains/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',
     'DiffusionSvnMergedCommitsQuery' => 'applications/diffusion/query/mergedcommits/svn',
     'DiffusionSvnRequest' => 'applications/diffusion/request/svn',
     'DiffusionSymbolController' => 'applications/diffusion/controller/symbol',
     'DiffusionSymbolQuery' => 'applications/diffusion/query/symbol',
     'DiffusionURITestCase' => 'applications/diffusion/request/base/__tests__',
     'DiffusionView' => 'applications/diffusion/view/base',
     'DrydockAllocator' => 'applications/drydock/allocator/resource',
     'DrydockAllocatorWorker' => 'applications/drydock/allocator/worker',
     'DrydockApacheWebrootBlueprint' => 'applications/drydock/blueprint/webroot/apache',
     'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/apache',
     'DrydockBlueprint' => 'applications/drydock/blueprint/base',
     'DrydockCommandInterface' => 'applications/drydock/interface/command/base',
     'DrydockConstants' => 'applications/drydock/constants/base',
     'DrydockController' => 'applications/drydock/controller/base',
     'DrydockDAO' => 'applications/drydock/storage/base',
     'DrydockEC2HostBlueprint' => 'applications/drydock/blueprint/ec2host',
     'DrydockInterface' => 'applications/drydock/interface/base',
     'DrydockLease' => 'applications/drydock/storage/lease',
     'DrydockLeaseListController' => 'applications/drydock/controller/leaselist',
     'DrydockLeaseStatus' => 'applications/drydock/constants/leasestatus',
     'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/local',
     'DrydockLocalHostBlueprint' => 'applications/drydock/blueprint/localhost',
     'DrydockLog' => 'applications/drydock/storage/log',
     'DrydockLogController' => 'applications/drydock/controller/log',
     'DrydockLogQuery' => 'applications/drydock/query/log',
     'DrydockPhabricatorApplicationBlueprint' => 'applications/drydock/blueprint/application/phabricator',
     'DrydockRemoteHostBlueprint' => 'applications/drydock/blueprint/remotehost',
     'DrydockResource' => 'applications/drydock/storage/resource',
     'DrydockResourceAllocateController' => 'applications/drydock/controller/resourceallocate',
     'DrydockResourceListController' => 'applications/drydock/controller/resourcelist',
     'DrydockResourceStatus' => 'applications/drydock/constants/resourcestatus',
     'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/ssh',
     'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/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',
     'HeraldEditLogQuery' => 'applications/herald/query/log',
     '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',
     'HeraldRuleEdit' => 'applications/herald/storage/edithistory',
     'HeraldRuleEditHistoryController' => 'applications/herald/controller/edithistory',
     'HeraldRuleEditHistoryView' => 'applications/herald/view/edithistory',
     'HeraldRuleListView' => 'applications/herald/view/rulelist',
     'HeraldRuleQuery' => 'applications/herald/query/rule',
     'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule',
     'HeraldRuleTypeConfig' => 'applications/herald/config/ruletype',
     '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',
     'JavelinReactorExample' => 'applications/uiexample/examples/reactor',
     'JavelinViewExample' => 'applications/uiexample/examples/client',
     'JavelinViewExampleServerView' => 'applications/uiexample/examples/client',
     'LiskDAO' => 'storage/lisk/dao',
     'LiskEphemeralObjectException' => 'storage/lisk/dao',
     'LiskIsolationTestCase' => 'storage/lisk/dao/__tests__',
     'LiskIsolationTestDAO' => 'storage/lisk/dao/__tests__',
     'LiskIsolationTestDAOException' => 'storage/lisk/dao/__tests__',
     'ManiphestAction' => 'applications/maniphest/constants/action',
     'ManiphestAuxiliaryFieldDefaultSpecification' => 'applications/maniphest/auxiliaryfield/default',
     'ManiphestAuxiliaryFieldSpecification' => 'applications/maniphest/auxiliaryfield/base',
     'ManiphestAuxiliaryFieldTypeException' => 'applications/maniphest/auxiliaryfield/typeexception',
     'ManiphestAuxiliaryFieldValidationException' => 'applications/maniphest/auxiliaryfield/validationexception',
     'ManiphestBatchEditController' => 'applications/maniphest/controller/batch',
     'ManiphestConstants' => 'applications/maniphest/constants/base',
     'ManiphestController' => 'applications/maniphest/controller/base',
     'ManiphestDAO' => 'applications/maniphest/storage/base',
     'ManiphestDefaultTaskExtensions' => 'applications/maniphest/extensions/task',
     'ManiphestExportController' => 'applications/maniphest/controller/export',
     'ManiphestReplyHandler' => 'applications/maniphest/replyhandler',
     'ManiphestReportController' => 'applications/maniphest/controller/report',
     'ManiphestSavedQuery' => 'applications/maniphest/storage/savedquery',
     'ManiphestSavedQueryDeleteController' => 'applications/maniphest/controller/savedquerydelete',
     'ManiphestSavedQueryEditController' => 'applications/maniphest/controller/savedqueryedit',
     'ManiphestSavedQueryListController' => 'applications/maniphest/controller/savedquerylist',
     'ManiphestSubpriorityController' => 'applications/maniphest/controller/subpriority',
     'ManiphestTask' => 'applications/maniphest/storage/task',
     'ManiphestTaskAuxiliaryStorage' => 'applications/maniphest/storage/auxiliary',
     'ManiphestTaskDescriptionChangeController' => 'applications/maniphest/controller/descriptionchange',
     'ManiphestTaskDescriptionPreviewController' => 'applications/maniphest/controller/descriptionpreview',
     'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail',
     'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit',
     'ManiphestTaskExtensions' => 'applications/maniphest/extensions/base',
     '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',
     'ManiphestTaskProjectsView' => 'applications/maniphest/view/taskprojects',
     'ManiphestTaskQuery' => 'applications/maniphest/query',
     'ManiphestTaskStatus' => 'applications/maniphest/constants/status',
     'ManiphestTaskSubscriber' => 'applications/maniphest/storage/subscriber',
     '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',
     'MetaMTAConstants' => 'applications/metamta/constants/base',
     'MetaMTANotificationType' => 'applications/metamta/constants/notificationtype',
     'Phabricator404Controller' => 'applications/base/controller/404',
     'PhabricatorAphlictTestPageController' => 'applications/notifications/controller/test',
     'PhabricatorAuditActionConstants' => 'applications/audit/constants/action',
     'PhabricatorAuditAddCommentController' => 'applications/audit/controller/addcomment',
     'PhabricatorAuditComment' => 'applications/audit/storage/auditcomment',
     'PhabricatorAuditCommentEditor' => 'applications/audit/editor/comment',
     'PhabricatorAuditCommitListView' => 'applications/audit/view/commitlist',
     'PhabricatorAuditCommitQuery' => 'applications/audit/query/commit',
     'PhabricatorAuditCommitStatusConstants' => 'applications/audit/constants/commitstatus',
     'PhabricatorAuditController' => 'applications/audit/controller/base',
     'PhabricatorAuditDAO' => 'applications/audit/storage/base',
     'PhabricatorAuditInlineComment' => 'applications/audit/storage/inlinecommment',
     'PhabricatorAuditListController' => 'applications/audit/controller/list',
     'PhabricatorAuditListView' => 'applications/audit/view/list',
     'PhabricatorAuditPreviewController' => 'applications/audit/controller/preview',
     'PhabricatorAuditQuery' => 'applications/audit/query/audit',
     'PhabricatorAuditReplyHandler' => 'applications/audit/replyhandler',
     'PhabricatorAuditStatusConstants' => 'applications/audit/constants/status',
     'PhabricatorAuthController' => 'applications/auth/controller/base',
     'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/browse',
     'PhabricatorCalendarController' => 'applications/calendar/controller/base',
     'PhabricatorChangesetResponse' => 'infrastructure/diff/response',
     'PhabricatorChatLogChannelListController' => 'applications/chatlog/controller/channellist',
     'PhabricatorChatLogChannelLogController' => 'applications/chatlog/controller/channellog',
     'PhabricatorChatLogConstants' => 'applications/chatlog/constants/base',
     'PhabricatorChatLogController' => 'applications/chatlog/controller/base',
     'PhabricatorChatLogDAO' => 'applications/chatlog/storage/base',
     'PhabricatorChatLogEvent' => 'applications/chatlog/storage/event',
     'PhabricatorChatLogEventType' => 'applications/chatlog/constants/eventtype',
     'PhabricatorChatLogQuery' => 'applications/chatlog/query',
     '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',
     'PhabricatorContentSource' => 'applications/metamta/contentsource/source',
     'PhabricatorContentSourceView' => 'applications/metamta/contentsource/view',
     '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',
     'PhabricatorDefaultFileStorageEngineSelector' => 'applications/files/engineselector/default',
     'PhabricatorDefaultSearchEngineSelector' => 'applications/search/selector/default',
     'PhabricatorDifferenceEngine' => 'infrastructure/diff/engine',
     'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
     'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
     'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
     'PhabricatorDirectoryCategoryViewController' => 'applications/directory/controller/categoryview',
     'PhabricatorDirectoryController' => 'applications/directory/controller/base',
     'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
     'PhabricatorDirectoryEditController' => 'applications/directory/controller/edit',
     'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
     'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
     'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
     'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
     'PhabricatorDisabledUserController' => 'applications/auth/controller/disabled',
     'PhabricatorDraft' => 'applications/draft/storage/draft',
     'PhabricatorDraftDAO' => 'applications/draft/storage/base',
     'PhabricatorEdgeConfig' => 'infrastructure/edges/constants/config',
     'PhabricatorEdgeConstants' => 'infrastructure/edges/constants/base',
     'PhabricatorEdgeEditor' => 'infrastructure/edges/editor/edge',
     'PhabricatorEdgeQuery' => 'infrastructure/edges/query/edge',
     'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
     'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
     'PhabricatorEnv' => 'infrastructure/env',
     'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__',
     'PhabricatorErrorExample' => 'applications/uiexample/examples/error',
     'PhabricatorEvent' => 'infrastructure/events/event',
     'PhabricatorEventEngine' => 'infrastructure/events/engine',
     'PhabricatorEventType' => 'infrastructure/events/constant/type',
     'PhabricatorFeedBuilder' => 'applications/feed/builder/feed',
     'PhabricatorFeedConstants' => 'applications/feed/constants/base',
     'PhabricatorFeedController' => 'applications/feed/controller/base',
     'PhabricatorFeedDAO' => 'applications/feed/storage/base',
     'PhabricatorFeedPublicStreamController' => 'applications/feed/controller/publicstream',
     'PhabricatorFeedQuery' => 'applications/feed/query',
     'PhabricatorFeedStory' => 'applications/feed/story/base',
     'PhabricatorFeedStoryAudit' => 'applications/feed/story/audit',
     'PhabricatorFeedStoryData' => 'applications/feed/storage/story',
     'PhabricatorFeedStoryDifferential' => 'applications/feed/story/differential',
     'PhabricatorFeedStoryManiphest' => 'applications/feed/story/maniphest',
     'PhabricatorFeedStoryPhriction' => 'applications/feed/story/phriction',
     'PhabricatorFeedStoryProject' => 'applications/feed/story/project',
     'PhabricatorFeedStoryPublisher' => 'applications/feed/publisher',
     'PhabricatorFeedStoryReference' => 'applications/feed/storage/storyreference',
     'PhabricatorFeedStoryStatus' => 'applications/feed/story/status',
     'PhabricatorFeedStoryTypeConstants' => 'applications/feed/constants/story',
     'PhabricatorFeedStoryUnknown' => 'applications/feed/story/unknown',
     'PhabricatorFeedStoryView' => 'applications/feed/view/story',
     'PhabricatorFeedView' => 'applications/feed/view/base',
     'PhabricatorFile' => 'applications/files/storage/file',
     'PhabricatorFileController' => 'applications/files/controller/base',
     'PhabricatorFileDAO' => 'applications/files/storage/base',
     'PhabricatorFileDataController' => 'applications/files/controller/data',
     'PhabricatorFileDeleteController' => 'applications/files/controller/delete',
     'PhabricatorFileDropUploadController' => 'applications/files/controller/dropupload',
     'PhabricatorFileImageMacro' => 'applications/files/storage/imagemacro',
     'PhabricatorFileInfoController' => 'applications/files/controller/info',
     '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',
     'PhabricatorFileSideNavView' => 'applications/files/view/sidenav',
     'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob',
     'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/configuration',
     'PhabricatorFileStorageEngine' => 'applications/files/engine/base',
     'PhabricatorFileStorageEngineSelector' => 'applications/files/engineselector/base',
     'PhabricatorFileTransformController' => 'applications/files/controller/transform',
     'PhabricatorFileUploadController' => 'applications/files/controller/upload',
     'PhabricatorFileUploadException' => 'applications/files/exception/upload',
     'PhabricatorFileUploadView' => 'applications/files/view/upload',
     'PhabricatorFlag' => 'applications/flag/storage/flag',
     'PhabricatorFlagColor' => 'applications/flag/constants/color',
     'PhabricatorFlagConstants' => 'applications/flag/constants/base',
     'PhabricatorFlagController' => 'applications/flag/controller/base',
     'PhabricatorFlagDAO' => 'applications/flag/storage/base',
     'PhabricatorFlagDeleteController' => 'applications/flag/controller/delete',
     'PhabricatorFlagEditController' => 'applications/flag/controller/edit',
     'PhabricatorFlagListController' => 'applications/flag/controller/list',
     'PhabricatorFlagListView' => 'applications/flag/view/list',
     'PhabricatorFlagQuery' => 'applications/flag/query/flag',
     'PhabricatorFormExample' => 'applications/uiexample/examples/form',
     'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector',
     'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing',
     'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector',
     'PhabricatorHash' => 'infrastructure/util/hash',
     'PhabricatorHelpController' => 'applications/help/controller/base',
     'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/keyboardshortcut',
     'PhabricatorIRCBot' => 'infrastructure/daemon/irc/bot',
     'PhabricatorIRCDifferentialNotificationHandler' => 'infrastructure/daemon/irc/handler/differentialnotification',
     'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base',
     'PhabricatorIRCLogHandler' => 'infrastructure/daemon/irc/handler/log',
     'PhabricatorIRCMacroHandler' => 'infrastructure/daemon/irc/handler/macro',
     'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message',
     'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname',
     'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol',
     'PhabricatorIRCWhatsNewHandler' => 'infrastructure/daemon/irc/handler/whatsnew',
     'PhabricatorImageTransformer' => 'applications/files/transform',
     'PhabricatorInfrastructureTestCase' => 'infrastructure/__tests__',
     'PhabricatorInlineCommentController' => 'infrastructure/diff/controller',
     'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/inline',
     'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/inline',
     'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/javelin',
     'PhabricatorJumpNavHandler' => 'applications/search/engine/jumpnav',
     'PhabricatorLintEngine' => 'infrastructure/lint/engine',
     'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
     'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/localdisk',
     'PhabricatorLocalTimeTestCase' => 'view/utils/__tests__',
     'PhabricatorLoginController' => 'applications/auth/controller/login',
     'PhabricatorLoginValidateController' => 'applications/auth/controller/validate',
     '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',
     'PhabricatorMarkupEngine' => 'applications/markup/engine',
     'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/mail',
     'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
     'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
     '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',
     'PhabricatorMetaMTAWorker' => 'applications/metamta/worker',
     'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/mysql',
     'PhabricatorNotificationsController' => 'applications/notifications/controller/base',
     'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/clientauthorization',
     'PhabricatorOAuthClientAuthorizationBaseController' => 'applications/oauthserver/controller/clientauthorization/base',
     'PhabricatorOAuthClientAuthorizationDeleteController' => 'applications/oauthserver/controller/clientauthorization/delete',
     'PhabricatorOAuthClientAuthorizationEditController' => 'applications/oauthserver/controller/clientauthorization/edit',
     'PhabricatorOAuthClientAuthorizationListController' => 'applications/oauthserver/controller/clientauthorization/list',
     'PhabricatorOAuthClientAuthorizationQuery' => 'applications/oauthserver/query/clientauthorization',
     'PhabricatorOAuthClientBaseController' => 'applications/oauthserver/controller/client/base',
     'PhabricatorOAuthClientDeleteController' => 'applications/oauthserver/controller/client/delete',
     'PhabricatorOAuthClientEditController' => 'applications/oauthserver/controller/client/edit',
     'PhabricatorOAuthClientListController' => 'applications/oauthserver/controller/client/list',
     'PhabricatorOAuthClientViewController' => 'applications/oauthserver/controller/client/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',
     'PhabricatorOAuthProviderGoogle' => 'applications/auth/oauth/provider/google',
     'PhabricatorOAuthProviderPhabricator' => 'applications/auth/oauth/provider/phabricator',
     'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base',
     'PhabricatorOAuthResponse' => 'applications/oauthserver/response',
     'PhabricatorOAuthServer' => 'applications/oauthserver/server',
     'PhabricatorOAuthServerAccessToken' => 'applications/oauthserver/storage/accesstoken',
     'PhabricatorOAuthServerAuthController' => 'applications/oauthserver/controller/auth',
     'PhabricatorOAuthServerAuthorizationCode' => 'applications/oauthserver/storage/authorizationcode',
     'PhabricatorOAuthServerClient' => 'applications/oauthserver/storage/client',
     'PhabricatorOAuthServerClientQuery' => 'applications/oauthserver/query/client',
     'PhabricatorOAuthServerController' => 'applications/oauthserver/controller/base',
     'PhabricatorOAuthServerDAO' => 'applications/oauthserver/storage/base',
     'PhabricatorOAuthServerScope' => 'applications/oauthserver/scope',
     'PhabricatorOAuthServerTestCase' => 'applications/oauthserver/server/__tests__',
     'PhabricatorOAuthServerTestController' => 'applications/oauthserver/controller/test',
     'PhabricatorOAuthServerTokenController' => 'applications/oauthserver/controller/token',
     'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink',
     'PhabricatorObjectAttachmentEditor' => 'applications/search/editor/attach',
     'PhabricatorObjectGraph' => 'applications/phid/graph',
     'PhabricatorObjectHandle' => 'applications/phid/handle',
     'PhabricatorObjectHandleConstants' => 'applications/phid/handle/const/base',
     'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
     'PhabricatorObjectHandleStatus' => 'applications/phid/handle/const/status',
     'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
     'PhabricatorOffsetPagedQuery' => 'infrastructure/query/offsetpaged',
     'PhabricatorOwnerPathQuery' => 'applications/owners/query/path',
     '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',
     'PhabricatorPHIDConstants' => 'applications/phid/constants',
     'PhabricatorPHIDController' => 'applications/phid/controller/base',
     'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
     'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup',
     'PhabricatorPaste' => 'applications/paste/storage/paste',
     'PhabricatorPasteController' => 'applications/paste/controller/base',
     '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',
     'PhabricatorProfileHeaderView' => 'view/layout/profileheader',
     'PhabricatorProject' => 'applications/project/storage/project',
     'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
     'PhabricatorProjectConstants' => 'applications/project/constants/base',
     'PhabricatorProjectController' => 'applications/project/controller/base',
     'PhabricatorProjectCreateController' => 'applications/project/controller/create',
     'PhabricatorProjectDAO' => 'applications/project/storage/base',
     'PhabricatorProjectEditor' => 'applications/project/editor/project',
     'PhabricatorProjectListController' => 'applications/project/controller/list',
     'PhabricatorProjectNameCollisionException' => 'applications/project/exception/namecollison',
     'PhabricatorProjectProfile' => 'applications/project/storage/profile',
     'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
     'PhabricatorProjectProfileEditController' => 'applications/project/controller/profileedit',
     'PhabricatorProjectQuery' => 'applications/project/query/project',
     'PhabricatorProjectStatus' => 'applications/project/constants/status',
     'PhabricatorProjectSubproject' => 'applications/project/storage/subproject',
     'PhabricatorProjectTransaction' => 'applications/project/storage/transaction',
     'PhabricatorProjectTransactionType' => 'applications/project/constants/transaction',
     'PhabricatorProjectUpdateController' => 'applications/project/controller/update',
     'PhabricatorQuery' => 'infrastructure/query/base',
     'PhabricatorRedirectController' => 'applications/base/controller/redirect',
     'PhabricatorRefreshCSRFController' => 'applications/auth/controller/refresh',
     'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
     'PhabricatorRemarkupRuleDifferentialHandle' => 'infrastructure/markup/remarkup/markuprule/handle/differential',
     'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion',
     'PhabricatorRemarkupRuleEmbedFile' => 'infrastructure/markup/remarkup/markuprule/embedobject',
     'PhabricatorRemarkupRuleImageMacro' => 'infrastructure/markup/remarkup/markuprule/imagemacro',
     'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest',
     'PhabricatorRemarkupRuleManiphestHandle' => 'infrastructure/markup/remarkup/markuprule/handle/maniphest',
     'PhabricatorRemarkupRuleMention' => 'infrastructure/markup/remarkup/markuprule/mention',
     'PhabricatorRemarkupRuleObjectHandle' => 'infrastructure/markup/remarkup/markuprule/handle',
     'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/remarkup/markuprule/objectname',
     'PhabricatorRemarkupRulePaste' => 'infrastructure/markup/remarkup/markuprule/paste',
     'PhabricatorRemarkupRulePhriction' => 'infrastructure/markup/remarkup/markuprule/phriction',
     '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',
     'PhabricatorRepositoryAuditRequest' => 'applications/repository/storage/auditrequest',
     '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',
     'PhabricatorRepositoryCommitOwnersWorker' => 'applications/repository/worker/owner',
     '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',
     'PhabricatorRepositoryGitCommitDiscoveryDaemonTestCase' => 'applications/repository/daemon/commitdiscovery/git/__tests__',
     'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/git',
     'PhabricatorRepositoryGitFetchDaemon' => 'applications/repository/daemon/gitfetch',
     'PhabricatorRepositoryListController' => 'applications/repository/controller/list',
     'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/mercurial',
     'PhabricatorRepositoryMercurialCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/mercurial',
     'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/mercurial',
     'PhabricatorRepositoryMercurialPullDaemon' => 'applications/repository/daemon/mercurialpull',
     'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/pulllocal',
     'PhabricatorRepositoryShortcut' => 'applications/repository/storage/shortcut',
     'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/svn',
     'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/svn',
     'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/svn',
     'PhabricatorRepositorySymbol' => 'applications/repository/storage/symbol',
     'PhabricatorRepositoryTestCase' => 'applications/repository/storage/repository/__tests__',
     'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype',
     'PhabricatorS3FileStorageEngine' => 'applications/files/engine/s3',
     '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',
     'PhabricatorSearchEngine' => 'applications/search/engine/base',
     'PhabricatorSearchEngineMySQL' => 'applications/search/engine/mysql',
     'PhabricatorSearchEngineSelector' => 'applications/search/selector/base',
     'PhabricatorSearchField' => 'applications/search/constants/field',
     'PhabricatorSearchIndexController' => 'applications/search/controller/index',
     'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest',
     'PhabricatorSearchPhrictionIndexer' => 'applications/search/index/indexer/phriction',
     'PhabricatorSearchQuery' => 'applications/search/storage/query',
     'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
     'PhabricatorSearchResultView' => 'applications/search/view/searchresult',
     'PhabricatorSearchScope' => 'applications/search/constants/scope',
     'PhabricatorSearchSelectController' => 'applications/search/controller/select',
     'PhabricatorSearchUserIndexer' => 'applications/search/index/indexer/user',
     'PhabricatorSetup' => 'infrastructure/setup',
     'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/choice',
     'PhabricatorSlowvoteComment' => 'applications/slowvote/storage/comment',
     'PhabricatorSlowvoteController' => 'applications/slowvote/controller/base',
     'PhabricatorSlowvoteCreateController' => 'applications/slowvote/controller/create',
     'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/base',
     'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/list',
     'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/option',
     'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/poll',
     'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/poll',
+    'PhabricatorSlug' => 'infrastructure/util/slug',
+    'PhabricatorSlugTestCase' => 'infrastructure/util/slug/__tests__',
     'PhabricatorSortTableExample' => 'applications/uiexample/examples/sorttable',
     'PhabricatorStandardPageView' => 'view/page/standard',
     'PhabricatorStatusController' => 'applications/status/base',
     'PhabricatorSymbolNameLinter' => 'infrastructure/lint/hook/xhpastsymbolname',
     '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',
     'PhabricatorTransactionView' => 'view/layout/transaction',
     'PhabricatorTransformedFile' => 'applications/files/storage/transformed',
     'PhabricatorTrivialTestCase' => 'infrastructure/testing/testcase/__tests__',
     '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',
     'PhabricatorUITooltipExample' => 'applications/uiexample/examples/tooltip',
     'PhabricatorUser' => 'applications/people/storage/user',
     'PhabricatorUserAccountSettingsPanelController' => 'applications/people/controller/settings/panels/account',
     'PhabricatorUserConduitSettingsPanelController' => 'applications/people/controller/settings/panels/conduit',
     'PhabricatorUserDAO' => 'applications/people/storage/base',
     'PhabricatorUserEmailPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/emailpref',
     'PhabricatorUserEmailSettingsPanelController' => 'applications/people/controller/settings/panels/email',
     'PhabricatorUserLog' => 'applications/people/storage/log',
     'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
     'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/oauth',
     'PhabricatorUserPasswordSettingsPanelController' => 'applications/people/controller/settings/panels/password',
     'PhabricatorUserPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/preferences',
     'PhabricatorUserPreferences' => 'applications/people/storage/preferences',
     'PhabricatorUserProfile' => 'applications/people/storage/profile',
     'PhabricatorUserProfileSettingsPanelController' => 'applications/people/controller/settings/panels/profile',
     'PhabricatorUserSSHKey' => 'applications/people/storage/usersshkey',
     'PhabricatorUserSSHKeysSettingsPanelController' => 'applications/people/controller/settings/panels/sshkeys',
     'PhabricatorUserSearchSettingsPanelController' => 'applications/people/controller/settings/panels/search',
     'PhabricatorUserSettingsController' => 'applications/people/controller/settings',
     'PhabricatorUserSettingsPanelController' => 'applications/people/controller/settings/panels/base',
     'PhabricatorUserTestCase' => 'applications/people/storage/user/__tests__',
     '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',
     'PhabricatorWorkerTaskUpdateController' => 'applications/daemon/controller/workertaskupdate',
     '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',
     'PhabricatorXHProfProfileView' => 'applications/xhprof/view/base',
     'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/monthyearexpiry',
     'PhortuneStripeBaseController' => 'applications/phortune/stripe/controller/base',
     'PhortuneStripePaymentFormView' => 'applications/phortune/stripe/view/paymentform',
     'PhortuneStripeTestPaymentFormController' => 'applications/phortune/stripe/controller/testpaymentform',
     'PhrictionActionConstants' => 'applications/phriction/constants/action',
     'PhrictionChangeType' => 'applications/phriction/constants/changetype',
     'PhrictionConstants' => 'applications/phriction/constants/base',
     'PhrictionContent' => 'applications/phriction/storage/content',
     'PhrictionController' => 'applications/phriction/controller/base',
     'PhrictionDAO' => 'applications/phriction/storage/base',
     'PhrictionDeleteController' => 'applications/phriction/controller/delete',
     'PhrictionDiffController' => 'applications/phriction/controller/diff',
     'PhrictionDocument' => 'applications/phriction/storage/document',
     'PhrictionDocumentController' => 'applications/phriction/controller/document',
     'PhrictionDocumentEditor' => 'applications/phriction/editor/document',
     'PhrictionDocumentPreviewController' => 'applications/phriction/controller/documentpreview',
     'PhrictionDocumentStatus' => 'applications/phriction/constants/documentstatus',
     'PhrictionDocumentTestCase' => 'applications/phriction/storage/document/__tests__',
     'PhrictionEditController' => 'applications/phriction/controller/edit',
     'PhrictionHistoryController' => 'applications/phriction/controller/history',
     'PhrictionListController' => 'applications/phriction/controller/list',
     'QueryFormattingTestCase' => 'storage/qsprintf/__tests__',
   ),
   'function' =>
   array(
     '_phabricator_date_format' => 'view/utils',
     '_qsprintf_check_scalar_type' => 'storage/qsprintf',
     '_qsprintf_check_type' => 'storage/qsprintf',
     'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
     'celerity_get_resource_uri' => '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_local_time' => 'view/utils',
     'phabricator_format_relative_time' => 'view/utils',
     'phabricator_format_units_generic' => 'view/utils',
     'phabricator_on_relative_date' => 'view/utils',
     'phabricator_relative_date' => 'view/utils',
     'phabricator_render_form' => 'infrastructure/javelin/markup',
     'phabricator_time' => 'view/utils',
     'phid_get_type' => 'applications/phid/utils',
     'phid_group_by_type' => 'applications/phid/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',
     'Aphront403Response' => 'AphrontWebpageResponse',
     'Aphront404Response' => 'AphrontWebpageResponse',
     'AphrontAjaxResponse' => 'AphrontResponse',
     'AphrontAttachedFileView' => 'AphrontView',
     'AphrontCSRFException' => 'AphrontException',
     'AphrontCalendarMonthView' => 'AphrontView',
     'AphrontContextBarView' => 'AphrontView',
     'AphrontCrumbsView' => 'AphrontView',
     'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
     'AphrontDialogResponse' => 'AphrontResponse',
     'AphrontDialogView' => 'AphrontView',
     'AphrontErrorView' => 'AphrontView',
     'AphrontFilePreviewView' => 'AphrontView',
     'AphrontFileResponse' => 'AphrontResponse',
     'AphrontFormCheckboxControl' => 'AphrontFormControl',
     'AphrontFormControl' => 'AphrontView',
     'AphrontFormDateControl' => 'AphrontFormControl',
     'AphrontFormDividerControl' => 'AphrontFormControl',
     'AphrontFormDragAndDropUploadControl' => 'AphrontFormControl',
     'AphrontFormFileControl' => 'AphrontFormControl',
     'AphrontFormInsetView' => 'AphrontView',
     'AphrontFormLayoutView' => 'AphrontView',
     'AphrontFormMarkupControl' => 'AphrontFormControl',
     'AphrontFormPasswordControl' => 'AphrontFormControl',
     'AphrontFormRadioButtonControl' => 'AphrontFormControl',
     'AphrontFormRecaptchaControl' => 'AphrontFormControl',
     'AphrontFormSelectControl' => 'AphrontFormControl',
     'AphrontFormStaticControl' => 'AphrontFormControl',
     'AphrontFormSubmitControl' => 'AphrontFormControl',
     'AphrontFormTextAreaControl' => 'AphrontFormControl',
     'AphrontFormTextControl' => 'AphrontFormControl',
     'AphrontFormToggleButtonsControl' => 'AphrontFormControl',
     'AphrontFormTokenizerControl' => 'AphrontFormControl',
     'AphrontFormView' => 'AphrontView',
     'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase',
     'AphrontHeadsupActionListView' => 'AphrontView',
     'AphrontHeadsupActionView' => 'AphrontView',
     'AphrontHeadsupView' => 'AphrontView',
     'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection',
     'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase',
     'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink',
     'AphrontJSONResponse' => 'AphrontResponse',
     'AphrontJavelinView' => 'AphrontView',
     'AphrontKeyboardShortcutsAvailableView' => 'AphrontView',
     'AphrontListFilterView' => 'AphrontView',
     'AphrontMiniPanelView' => 'AphrontView',
     'AphrontMySQLDatabaseConnection' => 'AphrontMySQLDatabaseConnectionBase',
     'AphrontMySQLDatabaseConnectionBase' => 'AphrontDatabaseConnection',
     'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase',
     'AphrontMySQLiDatabaseConnection' => 'AphrontMySQLDatabaseConnectionBase',
     'AphrontNullView' => 'AphrontView',
     'AphrontPHPHTTPSink' => 'AphrontHTTPSink',
     'AphrontPageView' => 'AphrontView',
     'AphrontPagerView' => 'AphrontView',
     'AphrontPanelView' => 'AphrontView',
     'AphrontPlainTextResponse' => 'AphrontResponse',
     'AphrontProxyResponse' => 'AphrontResponse',
     'AphrontQueryAccessDeniedException' => 'AphrontQueryRecoverableException',
     'AphrontQueryConnectionException' => 'AphrontQueryException',
     'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
     'AphrontQueryCountException' => 'AphrontQueryException',
     'AphrontQueryDuplicateKeyException' => 'AphrontQueryException',
     'AphrontQueryObjectMissingException' => 'AphrontQueryException',
     'AphrontQueryParameterException' => 'AphrontQueryException',
     'AphrontQueryRecoverableException' => 'AphrontQueryException',
     'AphrontQuerySchemaException' => 'AphrontQueryException',
     'AphrontRedirectException' => 'AphrontException',
     'AphrontRedirectResponse' => 'AphrontResponse',
     'AphrontReloadResponse' => 'AphrontRedirectResponse',
     'AphrontRequestFailureView' => 'AphrontView',
     'AphrontRequestTestCase' => 'PhabricatorTestCase',
     'AphrontSideNavFilterView' => 'AphrontView',
     'AphrontSideNavView' => 'AphrontView',
     'AphrontTableView' => 'AphrontView',
     'AphrontTokenizerTemplateView' => 'AphrontView',
     'AphrontTypeaheadTemplateView' => 'AphrontView',
     'AphrontWebpageResponse' => 'AphrontResponse',
     'CelerityResourceController' => 'AphrontController',
     'CelerityResourceGraph' => 'AbstractDirectedGraph',
     'CelerityResourceTransformerTestCase' => 'PhabricatorTestCase',
     'ConduitAPI_arcanist_Method' => 'ConduitAPIMethod',
     'ConduitAPI_arcanist_projectinfo_Method' => 'ConduitAPI_arcanist_Method',
     'ConduitAPI_audit_Method' => 'ConduitAPIMethod',
     'ConduitAPI_audit_query_Method' => 'ConduitAPI_audit_Method',
     'ConduitAPI_chatlog_Method' => 'ConduitAPIMethod',
     'ConduitAPI_chatlog_query_Method' => 'ConduitAPI_chatlog_Method',
     'ConduitAPI_chatlog_record_Method' => 'ConduitAPI_chatlog_Method',
     '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_createcomment_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_getrevisioncomments_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getrevisionfeedback_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_query_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPIMethod',
     'ConduitAPI_diffusion_findsymbols_Method' => 'ConduitAPIMethod',
     'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod',
     'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPIMethod',
     'ConduitAPI_feed_publish_Method' => 'ConduitAPIMethod',
     'ConduitAPI_feed_query_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_download_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_info_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
     'ConduitAPI_flag_Method' => 'ConduitAPIMethod',
     'ConduitAPI_flag_query_Method' => 'ConduitAPI_flag_Method',
     'ConduitAPI_macro_Method' => 'ConduitAPIMethod',
     'ConduitAPI_macro_query_Method' => 'ConduitAPI_macro_Method',
     'ConduitAPI_maniphest_Method' => 'ConduitAPIMethod',
     'ConduitAPI_maniphest_createtask_Method' => 'ConduitAPI_maniphest_Method',
     'ConduitAPI_maniphest_find_Method' => 'ConduitAPI_maniphest_Method',
     'ConduitAPI_maniphest_gettasktransactions_Method' => 'ConduitAPI_maniphest_Method',
     'ConduitAPI_maniphest_info_Method' => 'ConduitAPI_maniphest_Method',
     'ConduitAPI_maniphest_update_Method' => 'ConduitAPI_maniphest_Method',
     'ConduitAPI_paste_Method' => 'ConduitAPIMethod',
     'ConduitAPI_paste_create_Method' => 'ConduitAPI_paste_Method',
     'ConduitAPI_paste_info_Method' => 'ConduitAPI_paste_Method',
     'ConduitAPI_path_getowners_Method' => 'ConduitAPIMethod',
     'ConduitAPI_phid_Method' => 'ConduitAPIMethod',
     'ConduitAPI_phid_info_Method' => 'ConduitAPI_phid_Method',
     'ConduitAPI_phid_query_Method' => 'ConduitAPI_phid_Method',
     'ConduitAPI_phriction_Method' => 'ConduitAPIMethod',
     'ConduitAPI_phriction_edit_Method' => 'ConduitAPI_phriction_Method',
     'ConduitAPI_phriction_history_Method' => 'ConduitAPI_phriction_Method',
     'ConduitAPI_phriction_info_Method' => 'ConduitAPI_phriction_Method',
     'ConduitAPI_project_Method' => 'ConduitAPIMethod',
     'ConduitAPI_project_query_Method' => 'ConduitAPI_project_Method',
     'ConduitAPI_remarkup_process_Method' => 'ConduitAPIMethod',
     'ConduitAPI_slowvote_info_Method' => 'ConduitAPIMethod',
     'ConduitAPI_user_Method' => 'ConduitAPIMethod',
     'ConduitAPI_user_find_Method' => 'ConduitAPI_user_Method',
     'ConduitAPI_user_info_Method' => 'ConduitAPI_user_Method',
     'ConduitAPI_user_whoami_Method' => 'ConduitAPI_user_Method',
     'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
     'DarkConsoleController' => 'PhabricatorController',
     'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
     'DarkConsoleEventPlugin' => 'DarkConsolePlugin',
     'DarkConsoleEventPluginAPI' => 'PhutilEventListener',
     'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
     'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
     'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin',
     'DifferentialActionHasNoEffectException' => 'DifferentialException',
     'DifferentialAddCommentView' => 'AphrontView',
     'DifferentialAffectedPath' => 'DifferentialDAO',
     'DifferentialApplyPatchFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialArcanistProjectFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialAuditorsFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialAuthorFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialAuxiliaryField' => 'DifferentialDAO',
     'DifferentialBlameRevisionFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialBranchFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
     'DifferentialCCsFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialChangeset' => 'DifferentialDAO',
     'DifferentialChangesetDetailView' => 'AphrontView',
     'DifferentialChangesetListView' => 'AphrontView',
     'DifferentialChangesetViewController' => 'DifferentialController',
     'DifferentialComment' => 'DifferentialDAO',
     'DifferentialCommentMail' => 'DifferentialMail',
     'DifferentialCommentPreviewController' => 'DifferentialController',
     'DifferentialCommentSaveController' => 'DifferentialController',
     'DifferentialCommitsFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialController' => 'PhabricatorController',
     'DifferentialDAO' => 'PhabricatorLiskDAO',
     'DifferentialDateCreatedFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialDateModifiedFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialDefaultFieldSelector' => 'DifferentialFieldSelector',
     'DifferentialDependenciesFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialDiff' => 'DifferentialDAO',
     'DifferentialDiffContentMail' => 'DifferentialMail',
     'DifferentialDiffCreateController' => 'DifferentialController',
     'DifferentialDiffProperty' => 'DifferentialDAO',
     'DifferentialDiffTableOfContentsView' => 'AphrontView',
     'DifferentialDiffViewController' => 'DifferentialController',
     'DifferentialExceptionMail' => 'DifferentialMail',
     'DifferentialExportPatchFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialGitSVNIDFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialHostFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialHunk' => 'DifferentialDAO',
     'DifferentialInlineComment' => 'DifferentialDAO',
     'DifferentialInlineCommentEditController' => 'PhabricatorInlineCommentController',
     'DifferentialInlineCommentEditView' => 'AphrontView',
     'DifferentialInlineCommentPreviewController' => 'DifferentialController',
     'DifferentialInlineCommentView' => 'AphrontView',
     'DifferentialLinesFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialLintFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialLocalCommitsView' => 'AphrontView',
     'DifferentialManiphestTasksFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
     'DifferentialPathFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialPrimaryPaneView' => 'AphrontView',
     'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler',
     'DifferentialRevertPlanFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialReviewRequestMail' => 'DifferentialMail',
     'DifferentialReviewedByFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialReviewersFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialRevision' => 'DifferentialDAO',
     'DifferentialRevisionCommentListView' => 'AphrontView',
     'DifferentialRevisionCommentView' => 'AphrontView',
     'DifferentialRevisionDetailView' => 'AphrontView',
     'DifferentialRevisionEditController' => 'DifferentialController',
     'DifferentialRevisionIDFieldParserTestCase' => 'PhabricatorTestCase',
     'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialRevisionListController' => 'DifferentialController',
     'DifferentialRevisionListView' => 'AphrontView',
     'DifferentialRevisionStatsController' => 'DifferentialController',
     'DifferentialRevisionStatsView' => 'AphrontView',
     'DifferentialRevisionStatusFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
     'DifferentialRevisionViewController' => 'DifferentialController',
     'DifferentialSubscribeController' => 'DifferentialController',
     'DifferentialSummaryFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialTestPlanFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialTitleFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialUnitFieldSpecification' => 'DifferentialFieldSpecification',
     'DiffusionBranchTableView' => 'DiffusionView',
     'DiffusionBrowseController' => 'DiffusionController',
     'DiffusionBrowseFileController' => 'DiffusionController',
     'DiffusionBrowseTableView' => 'DiffusionView',
     'DiffusionChangeController' => 'DiffusionController',
     'DiffusionCommentListView' => 'AphrontView',
     'DiffusionCommentView' => 'AphrontView',
     'DiffusionCommitChangeTableView' => 'DiffusionView',
     'DiffusionCommitController' => 'DiffusionController',
     'DiffusionCommitParentsQuery' => 'DiffusionQuery',
     'DiffusionContainsQuery' => 'DiffusionQuery',
     'DiffusionController' => 'PhabricatorController',
     'DiffusionDiffController' => 'DiffusionController',
     'DiffusionDiffQuery' => 'DiffusionQuery',
     'DiffusionEmptyResultView' => 'DiffusionView',
     'DiffusionExternalController' => 'DiffusionController',
     'DiffusionFileContentQuery' => 'DiffusionQuery',
     'DiffusionGitBranchQuery' => 'DiffusionBranchQuery',
     'DiffusionGitBranchQueryTestCase' => 'PhabricatorTestCase',
     'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionGitCommitParentsQuery' => 'DiffusionCommitParentsQuery',
     'DiffusionGitContainsQuery' => 'DiffusionContainsQuery',
     'DiffusionGitDiffQuery' => 'DiffusionDiffQuery',
     'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
     'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionGitLastModifiedQuery' => 'DiffusionLastModifiedQuery',
     'DiffusionGitMergedCommitsQuery' => 'DiffusionMergedCommitsQuery',
     'DiffusionGitRequest' => 'DiffusionRequest',
     'DiffusionHistoryController' => 'DiffusionController',
     'DiffusionHistoryQuery' => 'DiffusionQuery',
     'DiffusionHistoryTableView' => 'DiffusionView',
     'DiffusionHomeController' => 'DiffusionController',
     'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController',
     'DiffusionLastModifiedController' => 'DiffusionController',
     'DiffusionLastModifiedQuery' => 'DiffusionQuery',
     'DiffusionMercurialBranchQuery' => 'DiffusionBranchQuery',
     'DiffusionMercurialBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionMercurialCommitParentsQuery' => 'DiffusionCommitParentsQuery',
     'DiffusionMercurialContainsQuery' => 'DiffusionContainsQuery',
     'DiffusionMercurialDiffQuery' => 'DiffusionDiffQuery',
     'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery',
     'DiffusionMercurialHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionMercurialLastModifiedQuery' => 'DiffusionLastModifiedQuery',
     'DiffusionMercurialMergedCommitsQuery' => 'DiffusionMergedCommitsQuery',
     'DiffusionMercurialRequest' => 'DiffusionRequest',
     'DiffusionMergedCommitsQuery' => 'DiffusionQuery',
     'DiffusionPathCompleteController' => 'DiffusionController',
     'DiffusionPathQueryTestCase' => 'PhabricatorTestCase',
     'DiffusionPathValidateController' => 'DiffusionController',
     'DiffusionRepositoryController' => 'DiffusionController',
     'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionSvnCommitParentsQuery' => 'DiffusionCommitParentsQuery',
     'DiffusionSvnContainsQuery' => 'DiffusionContainsQuery',
     'DiffusionSvnDiffQuery' => 'DiffusionDiffQuery',
     'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery',
     'DiffusionSvnHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionSvnLastModifiedQuery' => 'DiffusionLastModifiedQuery',
     'DiffusionSvnMergedCommitsQuery' => 'DiffusionMergedCommitsQuery',
     'DiffusionSvnRequest' => 'DiffusionRequest',
     'DiffusionSymbolController' => 'DiffusionController',
     'DiffusionURITestCase' => 'ArcanistPhutilTestCase',
     'DiffusionView' => 'AphrontView',
     'DrydockAllocatorWorker' => 'PhabricatorWorker',
     'DrydockApacheWebrootBlueprint' => 'DrydockBlueprint',
     'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface',
     'DrydockCommandInterface' => 'DrydockInterface',
     'DrydockController' => 'PhabricatorController',
     'DrydockDAO' => 'PhabricatorLiskDAO',
     'DrydockEC2HostBlueprint' => 'DrydockRemoteHostBlueprint',
     'DrydockLease' => 'DrydockDAO',
     'DrydockLeaseListController' => 'DrydockController',
     'DrydockLeaseStatus' => 'DrydockConstants',
     'DrydockLocalCommandInterface' => 'DrydockCommandInterface',
     'DrydockLocalHostBlueprint' => 'DrydockBlueprint',
     'DrydockLog' => 'DrydockDAO',
     'DrydockLogController' => 'DrydockController',
     'DrydockLogQuery' => 'PhabricatorOffsetPagedQuery',
     'DrydockPhabricatorApplicationBlueprint' => 'DrydockBlueprint',
     'DrydockRemoteHostBlueprint' => 'DrydockBlueprint',
     'DrydockResource' => 'DrydockDAO',
     'DrydockResourceAllocateController' => 'DrydockController',
     'DrydockResourceListController' => 'DrydockController',
     'DrydockResourceStatus' => 'DrydockConstants',
     'DrydockSSHCommandInterface' => 'DrydockCommandInterface',
     'DrydockWebrootInterface' => 'DrydockInterface',
     'HeraldAction' => 'HeraldDAO',
     'HeraldApplyTranscript' => 'HeraldDAO',
     'HeraldCommitAdapter' => 'HeraldObjectAdapter',
     'HeraldCondition' => 'HeraldDAO',
     'HeraldController' => 'PhabricatorController',
     'HeraldDAO' => 'PhabricatorLiskDAO',
     'HeraldDeleteController' => 'HeraldController',
     'HeraldDifferentialRevisionAdapter' => 'HeraldObjectAdapter',
     'HeraldDryRunAdapter' => 'HeraldObjectAdapter',
     'HeraldEditLogQuery' => 'PhabricatorOffsetPagedQuery',
     'HeraldHomeController' => 'HeraldController',
     'HeraldNewController' => 'HeraldController',
     'HeraldRule' => 'HeraldDAO',
     'HeraldRuleController' => 'HeraldController',
     'HeraldRuleEdit' => 'HeraldDAO',
     'HeraldRuleEditHistoryController' => 'HeraldController',
     'HeraldRuleEditHistoryView' => 'AphrontView',
     'HeraldRuleListView' => 'AphrontView',
     'HeraldRuleQuery' => 'PhabricatorOffsetPagedQuery',
     'HeraldTestConsoleController' => 'HeraldController',
     'HeraldTranscript' => 'HeraldDAO',
     'HeraldTranscriptController' => 'HeraldController',
     'HeraldTranscriptListController' => 'HeraldController',
     'JavelinReactorExample' => 'PhabricatorUIExample',
     'JavelinViewExample' => 'PhabricatorUIExample',
     'JavelinViewExampleServerView' => 'AphrontView',
     'LiskIsolationTestCase' => 'PhabricatorTestCase',
     'LiskIsolationTestDAO' => 'LiskDAO',
     'ManiphestAction' => 'PhrictionConstants',
     'ManiphestAuxiliaryFieldDefaultSpecification' => 'ManiphestAuxiliaryFieldSpecification',
     'ManiphestBatchEditController' => 'ManiphestController',
     'ManiphestController' => 'PhabricatorController',
     'ManiphestDAO' => 'PhabricatorLiskDAO',
     'ManiphestDefaultTaskExtensions' => 'ManiphestTaskExtensions',
     'ManiphestExportController' => 'ManiphestController',
     'ManiphestReplyHandler' => 'PhabricatorMailReplyHandler',
     'ManiphestReportController' => 'ManiphestController',
     'ManiphestSavedQuery' => 'ManiphestDAO',
     'ManiphestSavedQueryDeleteController' => 'ManiphestController',
     'ManiphestSavedQueryEditController' => 'ManiphestController',
     'ManiphestSavedQueryListController' => 'ManiphestController',
     'ManiphestSubpriorityController' => 'ManiphestController',
     'ManiphestTask' => 'ManiphestDAO',
     'ManiphestTaskAuxiliaryStorage' => 'ManiphestDAO',
     'ManiphestTaskDescriptionChangeController' => 'ManiphestController',
     'ManiphestTaskDescriptionPreviewController' => 'ManiphestController',
     'ManiphestTaskDetailController' => 'ManiphestController',
     'ManiphestTaskEditController' => 'ManiphestController',
     'ManiphestTaskListController' => 'ManiphestController',
     'ManiphestTaskListView' => 'ManiphestView',
     'ManiphestTaskOwner' => 'ManiphestConstants',
     'ManiphestTaskPriority' => 'ManiphestConstants',
     'ManiphestTaskProject' => 'ManiphestDAO',
     'ManiphestTaskProjectsView' => 'ManiphestView',
     'ManiphestTaskStatus' => 'ManiphestConstants',
     'ManiphestTaskSubscriber' => 'ManiphestDAO',
     'ManiphestTaskSummaryView' => 'ManiphestView',
     'ManiphestTransaction' => 'ManiphestDAO',
     'ManiphestTransactionDetailView' => 'ManiphestView',
     'ManiphestTransactionListView' => 'ManiphestView',
     'ManiphestTransactionPreviewController' => 'ManiphestController',
     'ManiphestTransactionSaveController' => 'ManiphestController',
     'ManiphestTransactionType' => 'ManiphestConstants',
     'ManiphestView' => 'AphrontView',
     'MetaMTANotificationType' => 'MetaMTAConstants',
     'Phabricator404Controller' => 'PhabricatorController',
     'PhabricatorAphlictTestPageController' => 'PhabricatorNotificationsController',
     'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController',
     'PhabricatorAuditComment' => 'PhabricatorAuditDAO',
     'PhabricatorAuditCommitListView' => 'AphrontView',
     'PhabricatorAuditController' => 'PhabricatorController',
     'PhabricatorAuditDAO' => 'PhabricatorLiskDAO',
     'PhabricatorAuditInlineComment' => 'PhabricatorAuditDAO',
     'PhabricatorAuditListController' => 'PhabricatorAuditController',
     'PhabricatorAuditListView' => 'AphrontView',
     'PhabricatorAuditPreviewController' => 'PhabricatorAuditController',
     'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler',
     'PhabricatorAuthController' => 'PhabricatorController',
     'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
     'PhabricatorCalendarController' => 'PhabricatorController',
     'PhabricatorChangesetResponse' => 'AphrontProxyResponse',
     'PhabricatorChatLogChannelListController' => 'PhabricatorChatLogController',
     'PhabricatorChatLogChannelLogController' => 'PhabricatorChatLogController',
     'PhabricatorChatLogController' => 'PhabricatorController',
     'PhabricatorChatLogDAO' => 'PhabricatorLiskDAO',
     'PhabricatorChatLogEvent' => 'PhabricatorChatLogDAO',
     'PhabricatorChatLogEventType' => 'PhabricatorChatLogConstants',
     'PhabricatorChatLogQuery' => 'PhabricatorOffsetPagedQuery',
     'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
     'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
     'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
     'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
     'PhabricatorConduitController' => 'PhabricatorController',
     'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
     'PhabricatorConduitLogController' => 'PhabricatorConduitController',
     'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
     'PhabricatorConduitTokenController' => 'PhabricatorConduitController',
     'PhabricatorContentSourceView' => 'AphrontView',
     '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',
     'PhabricatorDefaultFileStorageEngineSelector' => 'PhabricatorFileStorageEngineSelector',
     'PhabricatorDefaultSearchEngineSelector' => 'PhabricatorSearchEngineSelector',
     'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryViewController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryController' => 'PhabricatorController',
     'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorDirectoryEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
     'PhabricatorDisabledUserController' => 'PhabricatorAuthController',
     'PhabricatorDraft' => 'PhabricatorDraftDAO',
     'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
     'PhabricatorEdgeConfig' => 'PhabricatorEdgeConstants',
     'PhabricatorEdgeQuery' => 'PhabricatorQuery',
     'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
     'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
     'PhabricatorEnvTestCase' => 'PhabricatorTestCase',
     'PhabricatorErrorExample' => 'PhabricatorUIExample',
     'PhabricatorEvent' => 'PhutilEvent',
     'PhabricatorEventType' => 'PhutilEventType',
     'PhabricatorFeedController' => 'PhabricatorController',
     'PhabricatorFeedDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFeedPublicStreamController' => 'PhabricatorFeedController',
     'PhabricatorFeedStoryAudit' => 'PhabricatorFeedStory',
     'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO',
     'PhabricatorFeedStoryDifferential' => 'PhabricatorFeedStory',
     'PhabricatorFeedStoryManiphest' => 'PhabricatorFeedStory',
     'PhabricatorFeedStoryPhriction' => 'PhabricatorFeedStory',
     'PhabricatorFeedStoryProject' => 'PhabricatorFeedStory',
     'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO',
     'PhabricatorFeedStoryStatus' => 'PhabricatorFeedStory',
     'PhabricatorFeedStoryTypeConstants' => 'PhabricatorFeedConstants',
     'PhabricatorFeedStoryUnknown' => 'PhabricatorFeedStory',
     'PhabricatorFeedStoryView' => 'PhabricatorFeedView',
     'PhabricatorFeedView' => 'AphrontView',
     'PhabricatorFile' => 'PhabricatorFileDAO',
     'PhabricatorFileController' => 'PhabricatorController',
     'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFileDataController' => 'PhabricatorFileController',
     'PhabricatorFileDeleteController' => 'PhabricatorFileController',
     'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
     'PhabricatorFileImageMacro' => 'PhabricatorFileDAO',
     'PhabricatorFileInfoController' => 'PhabricatorFileController',
     'PhabricatorFileListController' => 'PhabricatorFileController',
     'PhabricatorFileMacroDeleteController' => 'PhabricatorFileController',
     'PhabricatorFileMacroEditController' => 'PhabricatorFileController',
     'PhabricatorFileMacroListController' => 'PhabricatorFileController',
     'PhabricatorFileProxyController' => 'PhabricatorFileController',
     'PhabricatorFileProxyImage' => 'PhabricatorFileDAO',
     'PhabricatorFileSideNavView' => 'AphrontView',
     'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
     'PhabricatorFileTransformController' => 'PhabricatorFileController',
     'PhabricatorFileUploadController' => 'PhabricatorFileController',
     'PhabricatorFileUploadView' => 'AphrontView',
     'PhabricatorFlag' => 'PhabricatorFlagDAO',
     'PhabricatorFlagColor' => 'PhabricatorFlagConstants',
     'PhabricatorFlagController' => 'PhabricatorController',
     'PhabricatorFlagDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFlagDeleteController' => 'PhabricatorFlagController',
     'PhabricatorFlagEditController' => 'PhabricatorFlagController',
     'PhabricatorFlagListController' => 'PhabricatorFlagController',
     'PhabricatorFlagListView' => 'AphrontView',
     'PhabricatorFormExample' => 'PhabricatorUIExample',
     'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon',
     'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker',
     'PhabricatorHelpController' => 'PhabricatorController',
     'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
     'PhabricatorIRCBot' => 'PhabricatorDaemon',
     'PhabricatorIRCDifferentialNotificationHandler' => 'PhabricatorIRCHandler',
     'PhabricatorIRCLogHandler' => 'PhabricatorIRCHandler',
     'PhabricatorIRCMacroHandler' => 'PhabricatorIRCHandler',
     'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler',
     'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler',
     'PhabricatorIRCWhatsNewHandler' => 'PhabricatorIRCHandler',
     'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase',
     'PhabricatorInlineCommentController' => 'PhabricatorController',
     'PhabricatorInlineSummaryView' => 'AphrontView',
     'PhabricatorJavelinLinter' => 'ArcanistLinter',
     'PhabricatorLintEngine' => 'PhutilLintEngine',
     'PhabricatorLiskDAO' => 'LiskDAO',
     'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
     'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase',
     'PhabricatorLoginController' => 'PhabricatorAuthController',
     'PhabricatorLoginValidateController' => 'PhabricatorAuthController',
     'PhabricatorLogoutController' => 'PhabricatorAuthController',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMetaMTAController' => 'PhabricatorController',
     'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
     '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',
     'PhabricatorMetaMTAWorker' => 'PhabricatorWorker',
     'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
     'PhabricatorNotificationsController' => 'PhabricatorController',
     'PhabricatorOAuthClientAuthorization' => 'PhabricatorOAuthServerDAO',
     'PhabricatorOAuthClientAuthorizationBaseController' => 'PhabricatorOAuthServerController',
     'PhabricatorOAuthClientAuthorizationDeleteController' => 'PhabricatorOAuthClientAuthorizationBaseController',
     'PhabricatorOAuthClientAuthorizationEditController' => 'PhabricatorOAuthClientAuthorizationBaseController',
     'PhabricatorOAuthClientAuthorizationListController' => 'PhabricatorOAuthClientAuthorizationBaseController',
     'PhabricatorOAuthClientAuthorizationQuery' => 'PhabricatorOffsetPagedQuery',
     'PhabricatorOAuthClientBaseController' => 'PhabricatorOAuthServerController',
     'PhabricatorOAuthClientDeleteController' => 'PhabricatorOAuthClientBaseController',
     'PhabricatorOAuthClientEditController' => 'PhabricatorOAuthClientBaseController',
     'PhabricatorOAuthClientListController' => 'PhabricatorOAuthClientBaseController',
     'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientBaseController',
     'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController',
     'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController',
     'PhabricatorOAuthFailureView' => 'AphrontView',
     'PhabricatorOAuthLoginController' => 'PhabricatorAuthController',
     'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthProviderGitHub' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthProviderGoogle' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthProviderPhabricator' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController',
     'PhabricatorOAuthResponse' => 'AphrontResponse',
     'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO',
     'PhabricatorOAuthServerAuthController' => 'PhabricatorAuthController',
     'PhabricatorOAuthServerAuthorizationCode' => 'PhabricatorOAuthServerDAO',
     'PhabricatorOAuthServerClient' => 'PhabricatorOAuthServerDAO',
     'PhabricatorOAuthServerClientQuery' => 'PhabricatorOffsetPagedQuery',
     'PhabricatorOAuthServerController' => 'PhabricatorController',
     'PhabricatorOAuthServerDAO' => 'PhabricatorLiskDAO',
     'PhabricatorOAuthServerTestCase' => 'PhabricatorTestCase',
     'PhabricatorOAuthServerTestController' => 'PhabricatorOAuthServerController',
     'PhabricatorOAuthServerTokenController' => 'PhabricatorAuthController',
     'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
     'PhabricatorObjectGraph' => 'AbstractDirectedGraph',
     'PhabricatorObjectHandleStatus' => 'PhabricatorObjectHandleConstants',
     'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery',
     'PhabricatorOwnersController' => 'PhabricatorController',
     'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
     'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
     'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO',
     'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO',
     'PhabricatorPHID' => 'PhabricatorPHIDDAO',
     'PhabricatorPHIDController' => 'PhabricatorController',
     'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
     'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
     'PhabricatorPaste' => 'PhabricatorPasteDAO',
     'PhabricatorPasteController' => 'PhabricatorController',
     'PhabricatorPasteDAO' => 'PhabricatorLiskDAO',
     'PhabricatorPasteListController' => 'PhabricatorPasteController',
     'PhabricatorPasteViewController' => 'PhabricatorPasteController',
     'PhabricatorPeopleController' => 'PhabricatorController',
     'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
     'PhabricatorProfileHeaderView' => 'AphrontView',
     'PhabricatorProject' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
     'PhabricatorProjectController' => 'PhabricatorController',
     'PhabricatorProjectCreateController' => 'PhabricatorProjectController',
     'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
     'PhabricatorProjectListController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
     'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectSubproject' => 'PhabricatorProjectDAO',
     'PhabricatorProjectTransaction' => 'PhabricatorProjectDAO',
     'PhabricatorProjectTransactionType' => 'PhabricatorProjectConstants',
     'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
     'PhabricatorRedirectController' => 'PhabricatorController',
     'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
     'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName',
     'PhabricatorRemarkupRuleDifferentialHandle' => 'PhabricatorRemarkupRuleObjectHandle',
     'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleEmbedFile' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleManiphest' => 'PhabricatorRemarkupRuleObjectName',
     'PhabricatorRemarkupRuleManiphestHandle' => 'PhabricatorRemarkupRuleObjectHandle',
     'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleObjectHandle' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRulePaste' => 'PhabricatorRemarkupRuleObjectName',
     'PhabricatorRemarkupRulePhriction' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleProxyImage' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule',
     'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryAuditRequest' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker',
     'PhabricatorRepositoryCommitTaskDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryController' => 'PhabricatorController',
     'PhabricatorRepositoryCreateController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon',
     'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'PhabricatorRepositoryCommitMessageDetailParser',
     'PhabricatorRepositoryDeleteController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryEditController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
     'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositoryGitCommitDiscoveryDaemonTestCase' => 'PhabricatorTestCase',
     'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
     'PhabricatorRepositoryGitFetchDaemon' => 'PhabricatorRepositoryPullLocalDaemon',
     'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
     'PhabricatorRepositoryMercurialCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
     'PhabricatorRepositoryMercurialPullDaemon' => 'PhabricatorRepositoryPullLocalDaemon',
     'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
     'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
     'PhabricatorRepositorySymbol' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryTestCase' => 'PhabricatorTestCase',
     'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
     'PhabricatorSearchAttachController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchBaseController' => 'PhabricatorController',
     'PhabricatorSearchCommitIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
     'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO',
     'PhabricatorSearchEngineMySQL' => 'PhabricatorSearchEngine',
     'PhabricatorSearchIndexController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchPhrictionIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
     'PhabricatorSearchResultView' => 'AphrontView',
     'PhabricatorSearchSelectController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchUserIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO',
     'PhabricatorSlowvoteComment' => 'PhabricatorSlowvoteDAO',
     'PhabricatorSlowvoteController' => 'PhabricatorController',
     'PhabricatorSlowvoteCreateController' => 'PhabricatorSlowvoteController',
     'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO',
     'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController',
     'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO',
     'PhabricatorSlowvotePoll' => 'PhabricatorSlowvoteDAO',
     'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController',
+    'PhabricatorSlugTestCase' => 'PhabricatorTestCase',
     'PhabricatorSortTableExample' => 'PhabricatorUIExample',
     'PhabricatorStandardPageView' => 'AphrontPageView',
     'PhabricatorStatusController' => 'PhabricatorController',
     'PhabricatorSymbolNameLinter' => 'ArcanistXHPASTLintNamingHook',
     'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon',
     'PhabricatorTestCase' => 'ArcanistPhutilTestCase',
     'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
     'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
     'PhabricatorTimer' => 'PhabricatorCountdownDAO',
     'PhabricatorTransactionView' => 'AphrontView',
     'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
     'PhabricatorTrivialTestCase' => 'PhabricatorTestCase',
     'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
     'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
     'PhabricatorUIExampleController' => 'PhabricatorController',
     'PhabricatorUIExampleRenderController' => 'PhabricatorUIExampleController',
     'PhabricatorUIListFilterExample' => 'PhabricatorUIExample',
     'PhabricatorUIPagerExample' => 'PhabricatorUIExample',
     'PhabricatorUITooltipExample' => 'PhabricatorUIExample',
     'PhabricatorUser' => 'PhabricatorUserDAO',
     'PhabricatorUserAccountSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserConduitSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
     'PhabricatorUserEmailPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserEmailSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserLog' => 'PhabricatorUserDAO',
     'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
     'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserPasswordSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
     'PhabricatorUserProfile' => 'PhabricatorUserDAO',
     'PhabricatorUserProfileSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserSSHKey' => 'PhabricatorUserDAO',
     'PhabricatorUserSSHKeysSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserSearchSettingsPanelController' => 'PhabricatorUserSettingsPanelController',
     'PhabricatorUserSettingsController' => 'PhabricatorPeopleController',
     'PhabricatorUserSettingsPanelController' => 'PhabricatorPeopleController',
     'PhabricatorUserTestCase' => 'PhabricatorTestCase',
     'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO',
     'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO',
     'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO',
     'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController',
     'PhabricatorWorkerTaskUpdateController' => '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' => 'PhabricatorXHProfProfileView',
     'PhabricatorXHProfProfileTopLevelView' => 'PhabricatorXHProfProfileView',
     'PhabricatorXHProfProfileView' => 'AphrontView',
     'PhortuneMonthYearExpiryControl' => 'AphrontFormControl',
     'PhortuneStripeBaseController' => 'PhabricatorController',
     'PhortuneStripePaymentFormView' => 'AphrontView',
     'PhortuneStripeTestPaymentFormController' => 'PhortuneStripeBaseController',
     'PhrictionActionConstants' => 'PhrictionConstants',
     'PhrictionChangeType' => 'PhrictionConstants',
     'PhrictionContent' => 'PhrictionDAO',
     'PhrictionController' => 'PhabricatorController',
     'PhrictionDAO' => 'PhabricatorLiskDAO',
     'PhrictionDeleteController' => 'PhrictionController',
     'PhrictionDiffController' => 'PhrictionController',
     'PhrictionDocument' => 'PhrictionDAO',
     'PhrictionDocumentController' => 'PhrictionController',
     'PhrictionDocumentPreviewController' => 'PhrictionController',
     'PhrictionDocumentStatus' => 'PhrictionConstants',
     'PhrictionDocumentTestCase' => 'PhabricatorTestCase',
     'PhrictionEditController' => 'PhrictionController',
     'PhrictionHistoryController' => 'PhrictionController',
     'PhrictionListController' => 'PhrictionController',
     'QueryFormattingTestCase' => 'PhabricatorTestCase',
   ),
   'requires_interface' =>
   array(
     'DefaultDatabaseConfigurationProvider' =>
     array(
       0 => 'DatabaseConfigurationProvider',
     ),
     'DifferentialInlineComment' =>
     array(
       0 => 'PhabricatorInlineCommentInterface',
     ),
     'PhabricatorAuditInlineComment' =>
     array(
       0 => 'PhabricatorInlineCommentInterface',
     ),
   ),
 ));
diff --git a/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php b/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php
index ab2dfd1908..eb26de8a2d 100644
--- a/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php
+++ b/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php
@@ -1,68 +1,68 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group conduit
  */
 final class ConduitAPI_phriction_history_Method
   extends ConduitAPI_phriction_Method {
 
   public function getMethodDescription() {
     return "Retrieve history about a Phriction docuemnt.";
   }
 
   public function defineParamTypes() {
     return array(
       'slug' => 'required string',
     );
   }
 
   public function defineReturnType() {
     return 'nonempty list';
   }
 
   public function defineErrorTypes() {
     return array(
       'ERR-BAD-DOCUMENT' => 'No such document exists.',
     );
   }
 
   protected function execute(ConduitAPIRequest $request) {
     $slug = $request->getValue('slug');
     $doc = id(new PhrictionDocument())->loadOneWhere(
       'slug = %s',
-      PhrictionDocument::normalizeSlug($slug));
+      PhabricatorSlug::normalize($slug));
     if (!$doc) {
       throw new ConduitException('ERR-BAD-DOCUMENT');
     }
 
     $content = id(new PhrictionContent())->loadAllWhere(
       'documentID = %d ORDER BY version DESC',
       $doc->getID());
 
     $results = array();
     foreach ($content as $version) {
       $results[] = $this->buildDocumentContentDictionary(
         $doc,
         $version);
     }
 
     return $results;
   }
 
 }
diff --git a/src/applications/conduit/method/phriction/history/__init__.php b/src/applications/conduit/method/phriction/history/__init__.php
index 1c09d18552..57cd63042b 100644
--- a/src/applications/conduit/method/phriction/history/__init__.php
+++ b/src/applications/conduit/method/phriction/history/__init__.php
@@ -1,17 +1,18 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/conduit/method/phriction/base');
 phutil_require_module('phabricator', 'applications/conduit/protocol/exception');
 phutil_require_module('phabricator', 'applications/phriction/storage/content');
 phutil_require_module('phabricator', 'applications/phriction/storage/document');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('ConduitAPI_phriction_history_Method.php');
diff --git a/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php b/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php
index d71fa916a9..c37ff4dc24 100644
--- a/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php
+++ b/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php
@@ -1,62 +1,62 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group conduit
  */
 final class ConduitAPI_phriction_info_Method
   extends ConduitAPI_phriction_Method {
 
   public function getMethodDescription() {
     return "Retrieve information about a Phriction document.";
   }
 
   public function defineParamTypes() {
     return array(
       'slug' => 'required string',
     );
   }
 
   public function defineReturnType() {
     return 'nonempty dict';
   }
 
   public function defineErrorTypes() {
     return array(
       'ERR-BAD-DOCUMENT' => 'No such document exists.',
     );
   }
 
   protected function execute(ConduitAPIRequest $request) {
     $slug = $request->getValue('slug');
 
     $doc = id(new PhrictionDocument())->loadOneWhere(
       'slug = %s',
-      PhrictionDocument::normalizeSlug($slug));
+      PhabricatorSlug::normalize($slug));
 
     if (!$doc) {
       throw new ConduitException('ERR-BAD-DOCUMENT');
     }
 
     $content = id(new PhrictionContent())->load($doc->getContentID());
     $doc->attachContent($content);
 
     return $this->buildDocumentInfoDictionary($doc);
   }
 
 }
diff --git a/src/applications/conduit/method/phriction/info/__init__.php b/src/applications/conduit/method/phriction/info/__init__.php
index a5d500f2d9..675d9fefdd 100644
--- a/src/applications/conduit/method/phriction/info/__init__.php
+++ b/src/applications/conduit/method/phriction/info/__init__.php
@@ -1,17 +1,18 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/conduit/method/phriction/base');
 phutil_require_module('phabricator', 'applications/conduit/protocol/exception');
 phutil_require_module('phabricator', 'applications/phriction/storage/content');
 phutil_require_module('phabricator', 'applications/phriction/storage/document');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('ConduitAPI_phriction_info_Method.php');
diff --git a/src/applications/phriction/controller/document/PhrictionDocumentController.php b/src/applications/phriction/controller/document/PhrictionDocumentController.php
index f0fe6e0b6a..3da625f360 100644
--- a/src/applications/phriction/controller/document/PhrictionDocumentController.php
+++ b/src/applications/phriction/controller/document/PhrictionDocumentController.php
@@ -1,384 +1,384 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group phriction
  */
 final class PhrictionDocumentController
   extends PhrictionController {
 
   private $slug;
 
   public function willProcessRequest(array $data) {
     $this->slug = $data['slug'];
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
     $user = $request->getUser();
 
-    $slug = PhrictionDocument::normalizeSlug($this->slug);
+    $slug = PhabricatorSlug::normalize($this->slug);
     if ($slug != $this->slug) {
       $uri = PhrictionDocument::getSlugURI($slug);
       // Canonicalize pages to their one true URI.
       return id(new AphrontRedirectResponse())->setURI($uri);
     }
 
     require_celerity_resource('phriction-document-css');
 
     $document = id(new PhrictionDocument())->loadOneWhere(
       'slug = %s',
       $slug);
 
     $breadcrumbs = $this->renderBreadcrumbs($slug);
     $version_note = null;
 
     if (!$document) {
       $create_uri = '/phriction/edit/?slug='.$slug;
 
       $page_content =
         '<div class="phriction-content">'.
           '<em>No content here!</em><br />'.
           'No document found at <tt>'.phutil_escape_html($slug).'</tt>. '.
           'You can <strong>'.
           phutil_render_tag(
             'a',
             array(
               'href' => $create_uri,
             ),
             'create a new document').'</strong>.'.
         '</div>';
       $page_title = 'Page Not Found';
       $button = phutil_render_tag(
         'a',
         array(
           'href' => $create_uri,
           'class' => 'green button',
         ),
         'Create Page');
       $buttons = $button;
     } else {
       $version = $request->getInt('v');
       if ($version) {
         $content = id(new PhrictionContent())->loadOneWhere(
           'documentID = %d AND version = %d',
           $document->getID(),
           $version);
         if (!$content) {
           return new Aphront404Response();
         }
 
         if ($content->getID() != $document->getContentID()) {
           $version_note = new AphrontErrorView();
           $version_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
           $version_note->setTitle('Older Version');
           $version_note->appendChild(
             'You are viewing an older version of this document, as it '.
             'appeared on '.
             phabricator_datetime($content->getDateCreated(), $user).'.');
         }
       } else {
         $content = id(new PhrictionContent())->load($document->getContentID());
       }
       $page_title = $content->getTitle();
 
       $project_phid = null;
       if (PhrictionDocument::isProjectSlug($slug)) {
         $project = id(new PhabricatorProject())->loadOneWhere(
           'phrictionSlug = %s',
           PhrictionDocument::getProjectSlugIdentifier($slug));
         $project_phid = $project->getPHID();
       }
 
       $phids = array_filter(
         array(
           $content->getAuthorPHID(),
           $project_phid,
         ));
       $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
 
       $age = time() - $content->getDateCreated();
       $age = floor($age / (60 * 60 * 24));
 
       if ($age < 1) {
         $when = 'today';
       } else if ($age == 1) {
         $when = 'yesterday';
       } else {
         $when = "{$age} days ago";
       }
 
 
       $project_info = null;
       if ($project_phid) {
         $project_info =
           '<br />This document is about the project '.
           $handles[$project_phid]->renderLink().'.';
       }
 
 
 
       $byline =
         '<div class="phriction-byline">'.
           "Last updated {$when} by ".
           $handles[$content->getAuthorPHID()]->renderLink().'.'.
           $project_info.
         '</div>';
 
 
       $doc_status = $document->getStatus();
       if ($doc_status == PhrictionDocumentStatus::STATUS_EXISTS) {
         $core_content = $content->renderContent();
       } else if ($doc_status == PhrictionDocumentStatus::STATUS_DELETED) {
         $notice = new AphrontErrorView();
         $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
         $notice->setTitle('Document Deleted');
         $notice->appendChild(
           'This document has been deleted. You can edit it to put new content '.
           'here, or use history to revert to an earlier version.');
         $core_content = $notice->render();
       } else {
         throw new Exception("Unknown document status '{$doc_status}'!");
       }
 
       $page_content =
         '<div class="phriction-content">'.
           $byline.
           $core_content.
         '</div>';
 
       $edit_button = phutil_render_tag(
         'a',
         array(
           'href' => '/phriction/edit/'.$document->getID().'/',
           'class' => 'button',
         ),
         'Edit Document');
       $history_button = phutil_render_tag(
         'a',
         array(
           'href' => PhrictionDocument::getSlugURI($slug, 'history'),
           'class' => 'button grey',
         ),
         'View History');
       // these float right so history_button which is right most goes first
       $buttons = $history_button.$edit_button;
     }
 
     if ($version_note) {
       $version_note = $version_note->render();
     }
 
     $children = $this->renderChildren($slug);
 
     $page =
       '<div class="phriction-header">'.
         $buttons.
         '<h1>'.phutil_escape_html($page_title).'</h1>'.
         $breadcrumbs.
       '</div>'.
       $version_note.
       $page_content.
       $children;
 
     return $this->buildStandardPageResponse(
       $page,
       array(
         'title'   => 'Phriction - '.$page_title,
       ));
 
   }
 
   private function renderBreadcrumbs($slug) {
 
     $ancestor_handles = array();
-    $ancestral_slugs = PhrictionDocument::getSlugAncestry($slug);
+    $ancestral_slugs = PhabricatorSlug::getAncestry($slug);
     $ancestral_slugs[] = $slug;
     if ($ancestral_slugs) {
       $empty_slugs = array_fill_keys($ancestral_slugs, null);
       $ancestors = id(new PhrictionDocument())->loadAllWhere(
         'slug IN (%Ls)',
         $ancestral_slugs);
       $ancestors = mpull($ancestors, null, 'getSlug');
 
       $ancestor_phids = mpull($ancestors, 'getPHID');
       $handles = array();
       if ($ancestor_phids) {
         $handles = id(new PhabricatorObjectHandleData($ancestor_phids))
           ->loadHandles();
       }
 
       $ancestor_handles = array();
       foreach ($ancestral_slugs as $slug) {
         if (isset($ancestors[$slug])) {
           $ancestor_handles[] = $handles[$ancestors[$slug]->getPHID()];
         } else {
           $handle = new PhabricatorObjectHandle();
-          $handle->setName(PhrictionDocument::getDefaultSlugTitle($slug));
+          $handle->setName(PhabricatorSlug::getDefaultTitle($slug));
           $handle->setURI(PhrictionDocument::getSlugURI($slug));
           $ancestor_handles[] = $handle;
         }
       }
     }
 
     $breadcrumbs = array();
     foreach ($ancestor_handles as $ancestor_handle) {
       $breadcrumbs[] = $ancestor_handle->renderLink();
     }
 
     $list = phutil_render_tag(
       'a',
       array(
         'href' => '/phriction/',
       ),
       'Document Index');
 
     return
       '<div class="phriction-breadcrumbs">'.
         $list.' &middot; '.
         '<span class="phriction-document-crumbs">'.
           implode(" \xC2\xBB ", $breadcrumbs).
         '</span>'.
       '</div>';
   }
 
   private function renderChildren($slug) {
     $document_dao = new PhrictionDocument();
     $content_dao = new PhrictionContent();
     $conn = $document_dao->establishConnection('r');
 
     $limit = 50;
-    $d_child = PhrictionDocument::getSlugDepth($slug) + 1;
-    $d_grandchild = PhrictionDocument::getSlugDepth($slug) + 2;
+    $d_child = PhabricatorSlug::getDepth($slug) + 1;
+    $d_grandchild = PhabricatorSlug::getDepth($slug) + 2;
 
     // Select children and grandchildren.
     $children = queryfx_all(
       $conn,
       'SELECT d.slug, d.depth, c.title FROM %T d JOIN %T c
         ON d.contentID = c.id
         WHERE d.slug LIKE %> AND d.depth IN (%d, %d)
           AND d.status = %d
         ORDER BY d.depth, c.title LIMIT %d',
       $document_dao->getTableName(),
       $content_dao->getTableName(),
       ($slug == '/' ? '' : $slug),
       $d_child,
       $d_grandchild,
       PhrictionDocumentStatus::STATUS_EXISTS,
       $limit);
 
     if (!$children) {
       return;
     }
 
     // We're going to render in one of three modes to try to accommodate
     // different information scales:
     //
     //  - If we found fewer than $limit rows, we know we have all the children
     //    and grandchildren and there aren't all that many. We can just render
     //    everything.
     //  - If we found $limit rows but the results included some grandchildren,
     //    we just throw them out and render only the children, as we know we
     //    have them all.
     //  - If we found $limit rows and the results have no grandchildren, we
     //    have a ton of children. Render them and then let the user know that
     //    this is not an exhaustive list.
 
     if (count($children) == $limit) {
       $more_children = true;
       foreach ($children as $child) {
         if ($child['depth'] == $d_grandchild) {
           $more_children = false;
         }
       }
       $show_grandchildren = false;
     } else {
       $show_grandchildren = true;
       $more_children = false;
     }
 
     $grandchildren = array();
     foreach ($children as $key => $child) {
       if ($child['depth'] == $d_child) {
         continue;
       } else {
         unset($children[$key]);
         if ($show_grandchildren) {
-          $ancestors = PhrictionDocument::getSlugAncestry($child['slug']);
+          $ancestors = PhabricatorSlug::getAncestry($child['slug']);
           $grandchildren[end($ancestors)][] = $child;
         }
       }
     }
 
     // Fill in any missing children.
     $known_slugs = ipull($children, null, 'slug');
     foreach ($grandchildren as $slug => $ignored) {
       if (empty($known_slugs[$slug])) {
         $children[] = array(
           'slug'    => $slug,
           'depth'   => $d_child,
-          'title'   => PhrictionDocument::getDefaultSlugTitle($slug),
+          'title'   => PhabricatorSlug::getDefaultTitle($slug),
           'empty'   => true,
         );
       }
     }
 
     $list = array();
     $list[] = '<ul>';
     foreach ($children as $child) {
       $list[] = $this->renderChildDocumentLink($child);
       $grand = idx($grandchildren, $child['slug'], array());
       if ($grand) {
         $list[] = '<ul>';
         foreach ($grand as $grandchild) {
           $list[] = $this->renderChildDocumentLink($grandchild);
         }
         $list[] = '</ul>';
       }
     }
     if ($more_children) {
       $list[] = '<li>More...</li>';
     }
     $list[] = '</ul>';
     $list = implode("\n", $list);
 
     return
       '<div class="phriction-children">'.
         '<div class="phriction-children-header">Document Hierarchy</div>'.
         $list.
       '</div>';
   }
 
   private function renderChildDocumentLink(array $info) {
     $title = nonempty($info['title'], '(Untitled Document)');
     $item = phutil_render_tag(
       'a',
       array(
         'href' => PhrictionDocument::getSlugURI($info['slug']),
       ),
       phutil_escape_html($title));
 
     if (isset($info['empty'])) {
       $item = '<em>'.$item.'</em>';
     }
 
     return '<li>'.$item.'</li>';
   }
 
 }
diff --git a/src/applications/phriction/controller/document/__init__.php b/src/applications/phriction/controller/document/__init__.php
index c486bb7f96..11871a5ad9 100644
--- a/src/applications/phriction/controller/document/__init__.php
+++ b/src/applications/phriction/controller/document/__init__.php
@@ -1,27 +1,28 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'aphront/response/404');
 phutil_require_module('phabricator', 'aphront/response/redirect');
 phutil_require_module('phabricator', 'applications/phid/handle');
 phutil_require_module('phabricator', 'applications/phid/handle/data');
 phutil_require_module('phabricator', 'applications/phriction/constants/documentstatus');
 phutil_require_module('phabricator', 'applications/phriction/controller/base');
 phutil_require_module('phabricator', 'applications/phriction/storage/content');
 phutil_require_module('phabricator', 'applications/phriction/storage/document');
 phutil_require_module('phabricator', 'applications/project/storage/project');
 phutil_require_module('phabricator', 'infrastructure/celerity/api');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 phutil_require_module('phabricator', 'storage/queryfx');
 phutil_require_module('phabricator', 'view/form/error');
 phutil_require_module('phabricator', 'view/utils');
 
 phutil_require_module('phutil', 'markup');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhrictionDocumentController.php');
diff --git a/src/applications/phriction/controller/edit/PhrictionEditController.php b/src/applications/phriction/controller/edit/PhrictionEditController.php
index 6a36fd81b7..fafd42bb8c 100644
--- a/src/applications/phriction/controller/edit/PhrictionEditController.php
+++ b/src/applications/phriction/controller/edit/PhrictionEditController.php
@@ -1,264 +1,264 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group phriction
  */
 final class PhrictionEditController
   extends PhrictionController {
 
   private $id;
 
   public function willProcessRequest(array $data) {
     $this->id = idx($data, 'id');
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
     $user = $request->getUser();
 
     if ($this->id) {
       $document = id(new PhrictionDocument())->load($this->id);
       if (!$document) {
         return new Aphront404Response();
       }
 
       $revert = $request->getInt('revert');
       if ($revert) {
         $content = id(new PhrictionContent())->loadOneWhere(
           'documentID = %d AND version = %d',
           $document->getID(),
           $revert);
         if (!$content) {
           return new Aphront404Response();
         }
       } else {
         $content = id(new PhrictionContent())->load($document->getContentID());
       }
 
     } else {
       $slug = $request->getStr('slug');
-      $slug = PhrictionDocument::normalizeSlug($slug);
+      $slug = PhabricatorSlug::normalize($slug);
       if (!$slug) {
         return new Aphront404Response();
       }
 
       $document = id(new PhrictionDocument())->loadOneWhere(
         'slug = %s',
         $slug);
 
       if ($document) {
         $content = id(new PhrictionContent())->load($document->getContentID());
       } else {
         $document = new PhrictionDocument();
         $document->setSlug($slug);
 
         $content  = new PhrictionContent();
         $content->setSlug($slug);
 
-        $default_title = PhrictionDocument::getDefaultSlugTitle($slug);
+        $default_title = PhabricatorSlug::getDefaultTitle($slug);
         $content->setTitle($default_title);
       }
     }
 
     if ($request->getBool('nodraft')) {
       $draft = null;
       $draft_key = null;
     } else {
       if ($document->getPHID()) {
         $draft_key = $document->getPHID().':'.$content->getVersion();
       } else {
         $draft_key = 'phriction:'.$content->getSlug();
       }
       $draft = id(new PhabricatorDraft())->loadOneWhere(
         'authorPHID = %s AND draftKey = %s',
         $user->getPHID(),
         $draft_key);
     }
 
     require_celerity_resource('phriction-document-css');
 
     $e_title = true;
     $errors = array();
 
     if ($request->isFormPost()) {
       $title = $request->getStr('title');
 
       if (!strlen($title)) {
         $e_title = 'Required';
         $errors[] = 'Document title is required.';
       } else {
         $e_title = null;
       }
 
       if (!count($errors)) {
         $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))
           ->setUser($user)
           ->setTitle($title)
           ->setContent($request->getStr('content'))
           ->setDescription($request->getStr('description'));
 
         $editor->save();
 
         if ($draft) {
           $draft->delete();
         }
 
         $uri = PhrictionDocument::getSlugURI($document->getSlug());
         return id(new AphrontRedirectResponse())->setURI($uri);
       }
     }
 
     $error_view = null;
     if ($errors) {
       $error_view = id(new AphrontErrorView())
         ->setTitle('Form Errors')
         ->setErrors($errors);
     }
 
     if ($document->getID()) {
       $panel_header = 'Edit Phriction Document';
       $submit_button = 'Save Changes';
       $delete_button = phutil_render_tag(
         'a',
         array(
           'href' => '/phriction/delete/'.$document->getID().'/',
           'class' => 'grey button',
         ),
         'Delete Document');
     } else {
       $panel_header = 'Create New Phriction Document';
       $submit_button = 'Create Document';
       $delete_button = null;
     }
 
     $uri = $document->getSlug();
     $uri = PhrictionDocument::getSlugURI($uri);
     $uri = PhabricatorEnv::getProductionURI($uri);
 
     $remarkup_reference = phutil_render_tag(
       'a',
       array(
         'href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html'),
         'tabindex' => '-1',
         'target' => '_blank',
       ),
       'Formatting Reference');
 
     $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
 
     if ($draft &&
         strlen($draft->getDraft()) &&
         ($draft->getDraft() != $content->getContent())) {
       $content_text = $draft->getDraft();
 
       $discard = phutil_render_tag(
         'a',
         array(
           'href' => $request->getRequestURI()->alter('nodraft', true),
         ),
         'discard this draft');
 
       $draft_note = new AphrontErrorView();
       $draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
       $draft_note->setTitle('Recovered Draft');
       $draft_note->appendChild(
         '<p>Showing a saved draft of your edits, you can '.$discard.'.</p>');
     } else {
       $content_text = $content->getContent();
       $draft_note = null;
     }
 
     $form = id(new AphrontFormView())
       ->setUser($user)
       ->setAction($request->getRequestURI()->getPath())
       ->addHiddenInput('slug', $document->getSlug())
       ->addHiddenInput('nodraft', $request->getBool('nodraft'))
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel('Title')
           ->setValue($content->getTitle())
           ->setError($e_title)
           ->setName('title'))
       ->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('URI')
           ->setValue($uri))
       ->appendChild(
         id(new AphrontFormTextAreaControl())
           ->setLabel('Content')
           ->setValue($content_text)
           ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
           ->setName('content')
           ->setID('document-textarea')
           ->setEnableDragAndDropFileUploads(true)
           ->setCaption($remarkup_reference))
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel('Edit Notes')
           ->setValue($content->getDescription())
           ->setError(null)
           ->setName('description'))
       ->appendChild(
         id(new AphrontFormSubmitControl())
           ->addCancelButton($cancel_uri)
           ->setValue($submit_button));
 
     $panel = id(new AphrontPanelView())
       ->setWidth(AphrontPanelView::WIDTH_WIDE)
       ->setHeader($panel_header)
       ->appendChild($form);
 
     if ($delete_button) {
       $panel->addButton($delete_button);
     }
 
     $preview_panel =
       '<div class="aphront-panel-preview aphront-panel-preview-wide">
         <div class="phriction-document-preview-header">
           Document Preview
         </div>
         <div id="document-preview">
           <div class="aphront-panel-preview-loading-text">
             Loading preview...
           </div>
         </div>
       </div>';
 
     Javelin::initBehavior(
       'phriction-document-preview',
       array(
         'preview'   => 'document-preview',
         'textarea'  => 'document-textarea',
         'uri'       => '/phriction/preview/?draftkey='.$draft_key,
       ));
 
     return $this->buildStandardPageResponse(
       array(
         $draft_note,
         $error_view,
         $panel,
         $preview_panel,
       ),
       array(
         'title' => 'Edit Document',
       ));
   }
 
 }
diff --git a/src/applications/phriction/controller/edit/__init__.php b/src/applications/phriction/controller/edit/__init__.php
index b2d470df71..ba786145d3 100644
--- a/src/applications/phriction/controller/edit/__init__.php
+++ b/src/applications/phriction/controller/edit/__init__.php
@@ -1,31 +1,32 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'aphront/response/404');
 phutil_require_module('phabricator', 'aphront/response/redirect');
 phutil_require_module('phabricator', 'applications/draft/storage/draft');
 phutil_require_module('phabricator', 'applications/phriction/controller/base');
 phutil_require_module('phabricator', 'applications/phriction/editor/document');
 phutil_require_module('phabricator', 'applications/phriction/storage/content');
 phutil_require_module('phabricator', 'applications/phriction/storage/document');
 phutil_require_module('phabricator', 'infrastructure/celerity/api');
 phutil_require_module('phabricator', 'infrastructure/env');
 phutil_require_module('phabricator', 'infrastructure/javelin/api');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 phutil_require_module('phabricator', 'view/form/base');
 phutil_require_module('phabricator', 'view/form/control/static');
 phutil_require_module('phabricator', 'view/form/control/submit');
 phutil_require_module('phabricator', 'view/form/control/text');
 phutil_require_module('phabricator', 'view/form/control/textarea');
 phutil_require_module('phabricator', 'view/form/error');
 phutil_require_module('phabricator', 'view/layout/panel');
 
 phutil_require_module('phutil', 'markup');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhrictionEditController.php');
diff --git a/src/applications/phriction/controller/history/PhrictionHistoryController.php b/src/applications/phriction/controller/history/PhrictionHistoryController.php
index 9dabf13ed1..c6af894098 100644
--- a/src/applications/phriction/controller/history/PhrictionHistoryController.php
+++ b/src/applications/phriction/controller/history/PhrictionHistoryController.php
@@ -1,171 +1,171 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group phriction
  */
 final class PhrictionHistoryController
   extends PhrictionController {
 
   private $slug;
 
   public function willProcessRequest(array $data) {
     $this->slug = $data['slug'];
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
     $user = $request->getUser();
 
     $document = id(new PhrictionDocument())->loadOneWhere(
       'slug = %s',
-      PhrictionDocument::normalizeSlug($this->slug));
+      PhabricatorSlug::normalize($this->slug));
 
     if (!$document) {
       return new Aphront404Response();
     }
 
     $current = id(new PhrictionContent())->load($document->getContentID());
 
     $pager = new AphrontPagerView();
     $pager->setOffset($request->getInt('page'));
     $pager->setURI($request->getRequestURI(), 'page');
 
     $history = id(new PhrictionContent())->loadAllWhere(
       'documentID = %d ORDER BY version DESC LIMIT %d, %d',
       $document->getID(),
       $pager->getOffset(),
       $pager->getPageSize() + 1);
     $history = $pager->sliceResults($history);
 
     $author_phids = mpull($history, 'getAuthorPHID');
     $handles = id(new PhabricatorObjectHandleData($author_phids))
       ->loadHandles();
 
     $rows = array();
     foreach ($history as $content) {
 
       $uri = PhrictionDocument::getSlugURI($document->getSlug());
       $version = $content->getVersion();
 
       $diff_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/');
 
       $vs_previous = '<em>Created</em>';
       if ($content->getVersion() != 1) {
         $uri = $diff_uri
           ->alter('l', $content->getVersion() - 1)
           ->alter('r', $content->getVersion());
         $vs_previous = phutil_render_tag(
           'a',
           array(
             'href' => $uri,
           ),
           'Show Change');
       }
 
       $vs_head = '<em>Current</em>';
       if ($content->getID() != $document->getContentID()) {
         $uri = $diff_uri
           ->alter('l', $content->getVersion())
           ->alter('r', $current->getVersion());
 
         $vs_head = phutil_render_tag(
           'a',
           array(
             'href' => $uri,
           ),
           'Show Later Changes');
       }
 
       $change_type = PhrictionChangeType::getChangeTypeLabel(
         $content->getChangeType());
 
       $rows[] = array(
         phabricator_date($content->getDateCreated(), $user),
         phabricator_time($content->getDateCreated(), $user),
         phutil_render_tag(
           'a',
           array(
             'href' => $uri.'?v='.$version,
           ),
           'Version '.$version),
         $handles[$content->getAuthorPHID()]->renderLink(),
         $change_type,
         phutil_escape_html($content->getDescription()),
         $vs_previous,
         $vs_head,
       );
     }
 
     $crumbs = new AphrontCrumbsView();
     $crumbs->setCrumbs(
       array(
         'Phriction',
         phutil_render_tag(
           'a',
           array(
             'href' => PhrictionDocument::getSlugURI($document->getSlug()),
           ),
           phutil_escape_html($current->getTitle())
         ),
         'History',
       ));
 
 
     $table = new AphrontTableView($rows);
     $table->setHeaders(
       array(
         'Date',
         'Time',
         'Version',
         'Author',
         'Type',
         'Description',
         'Against Previous',
         'Against Current',
       ));
     $table->setColumnClasses(
       array(
         '',
         'right',
         'pri',
         '',
         '',
         'wide',
         '',
         '',
       ));
 
     $panel = new AphrontPanelView();
     $panel->setHeader('Document History');
     $panel->appendChild($table);
     $panel->appendChild($pager);
 
     return $this->buildStandardPageResponse(
       array(
         $crumbs,
         $panel,
       ),
       array(
         'title'     => 'Document History',
       ));
 
   }
 
 }
diff --git a/src/applications/phriction/controller/history/__init__.php b/src/applications/phriction/controller/history/__init__.php
index f47ab5a76f..7d8840b1ac 100644
--- a/src/applications/phriction/controller/history/__init__.php
+++ b/src/applications/phriction/controller/history/__init__.php
@@ -1,26 +1,27 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'aphront/response/404');
 phutil_require_module('phabricator', 'applications/phid/handle/data');
 phutil_require_module('phabricator', 'applications/phriction/constants/changetype');
 phutil_require_module('phabricator', 'applications/phriction/controller/base');
 phutil_require_module('phabricator', 'applications/phriction/storage/content');
 phutil_require_module('phabricator', 'applications/phriction/storage/document');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 phutil_require_module('phabricator', 'view/control/pager');
 phutil_require_module('phabricator', 'view/control/table');
 phutil_require_module('phabricator', 'view/layout/crumbs');
 phutil_require_module('phabricator', 'view/layout/panel');
 phutil_require_module('phabricator', 'view/utils');
 
 phutil_require_module('phutil', 'markup');
 phutil_require_module('phutil', 'parser/uri');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhrictionHistoryController.php');
diff --git a/src/applications/phriction/editor/document/PhrictionDocumentEditor.php b/src/applications/phriction/editor/document/PhrictionDocumentEditor.php
index 17b6d0c0e9..7e0903efa0 100644
--- a/src/applications/phriction/editor/document/PhrictionDocumentEditor.php
+++ b/src/applications/phriction/editor/document/PhrictionDocumentEditor.php
@@ -1,241 +1,241 @@
 <?php
 
 /*
- * Copyright 2011 Facebook, Inc.
+ * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * Create or update Phriction documents.
  *
  * @group phriction
  */
 final class PhrictionDocumentEditor {
 
   private $document;
   private $content;
 
   private $user;
 
   private $newTitle;
   private $newContent;
   private $description;
 
   private function __construct() {
     // <restricted>
   }
 
   public static function newForSlug($slug) {
-    $slug = PhrictionDocument::normalizeSlug($slug);
+    $slug = PhabricatorSlug::normalize($slug);
     $document = id(new PhrictionDocument())->loadOneWhere(
       'slug = %s',
       $slug);
     $content = null;
 
     if ($document) {
       $content = id(new PhrictionContent())->load($document->getContentID());
     } else {
       $document = new PhrictionDocument();
       $document->setSlug($slug);
     }
 
     if (!$content) {
-      $default_title = PhrictionDocument::getDefaultSlugTitle($slug);
+      $default_title = PhabricatorSlug::getDefaultTitle($slug);
       $content = new PhrictionContent();
       $content->setSlug($slug);
       $content->setTitle($default_title);
       $content->setContent('');
     }
 
     $obj = new PhrictionDocumentEditor();
     $obj->document = $document;
     $obj->content  = $content;
 
     return $obj;
   }
 
   public function setUser(PhabricatorUser $user) {
     $this->user = $user;
     return $this;
   }
 
   public function setTitle($title) {
     $this->newTitle = $title;
     return $this;
   }
 
   public function setContent($content) {
     $this->newContent = $content;
     return $this;
   }
 
   public function setDescription($description) {
     $this->description = $description;
     return $this;
   }
 
   public function getDocument() {
     return $this->document;
   }
 
   public function delete() {
     if (!$this->user) {
       throw new Exception("Call setUser() before deleting a document!");
     }
 
     // TODO: Should we do anything about deleting an already-deleted document?
     // We currently allow it.
 
     $document = $this->document;
     $content  = $this->content;
 
     $new_content = $this->buildContentTemplate($document, $content);
 
     $new_content->setChangeType(PhrictionChangeType::CHANGE_DELETE);
     $new_content->setContent('');
 
     return $this->updateDocument($document, $content, $new_content);
   }
 
   public function save() {
     if (!$this->user) {
       throw new Exception("Call setUser() before updating a document!");
     }
 
     if ($this->newContent === '') {
       // If this is an edit which deletes all the content, just treat it as
       // a delete. NOTE: null means "don't change the content", not "delete
       // the page"! Thus the strict type check.
       return $this->delete();
     }
 
     $document = $this->document;
     $content  = $this->content;
 
     $new_content = $this->buildContentTemplate($document, $content);
 
     return $this->updateDocument($document, $content, $new_content);
   }
 
   private function buildContentTemplate(
     PhrictionDocument $document,
     PhrictionContent $content) {
 
     $new_content = new PhrictionContent();
     $new_content->setSlug($document->getSlug());
     $new_content->setAuthorPHID($this->user->getPHID());
     $new_content->setChangeType(PhrictionChangeType::CHANGE_EDIT);
 
     $new_content->setTitle(
       coalesce(
         $this->newTitle,
         $content->getTitle()));
 
     $new_content->setContent(
       coalesce(
         $this->newContent,
         $content->getContent()));
 
     if (strlen($this->description)) {
       $new_content->setDescription($this->description);
     }
 
     return $new_content;
   }
 
   private function updateDocument($document, $content, $new_content) {
 
     $is_new = false;
     if (!$document->getID()) {
       $is_new = true;
     }
 
     $new_content->setVersion($content->getVersion() + 1);
 
     $change_type = $new_content->getChangeType();
     switch ($change_type) {
       case PhrictionChangeType::CHANGE_EDIT:
         $doc_status = PhrictionDocumentStatus::STATUS_EXISTS;
         $feed_action = $is_new
           ? PhrictionActionConstants::ACTION_CREATE
           : PhrictionActionConstants::ACTION_EDIT;
         break;
       case PhrictionChangeType::CHANGE_DELETE:
         $doc_status = PhrictionDocumentStatus::STATUS_DELETED;
         $feed_action = PhrictionActionConstants::ACTION_DELETE;
         if ($is_new) {
           throw new Exception(
             "You can not delete a document which doesn't exist yet!");
         }
         break;
       default:
         throw new Exception(
           "Unsupported content change type '{$change_type}'!");
     }
 
     $document->setStatus($doc_status);
 
     // TODO: This should be transactional.
 
     if ($is_new) {
       $document->save();
     }
 
     $new_content->setDocumentID($document->getID());
     $new_content->save();
 
     $document->setContentID($new_content->getID());
     $document->save();
 
     $document->attachContent($new_content);
     PhabricatorSearchPhrictionIndexer::indexDocument($document);
 
     $project_phid = null;
     $slug = $document->getSlug();
     if (PhrictionDocument::isProjectSlug($slug)) {
       $project = id(new PhabricatorProject())->loadOneWhere(
         'phrictionSlug = %s',
         PhrictionDocument::getProjectSlugIdentifier($slug));
       if ($project) {
         $project_phid = $project->getPHID();
       }
     }
 
     $related_phids = array(
       $document->getPHID(),
       $this->user->getPHID(),
     );
 
     if ($project_phid) {
       $related_phids[] = $project_phid;
     }
 
     id(new PhabricatorFeedStoryPublisher())
       ->setRelatedPHIDs($related_phids)
       ->setStoryAuthorPHID($this->user->getPHID())
       ->setStoryTime(time())
       ->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PHRICTION)
       ->setStoryData(
         array(
           'phid'    => $document->getPHID(),
           'action'  => $feed_action,
           'content' => phutil_utf8_shorten($new_content->getContent(), 140),
           'project' => $project_phid,
         ))
       ->publish();
 
     return $this;
   }
 
 }
diff --git a/src/applications/phriction/editor/document/__init__.php b/src/applications/phriction/editor/document/__init__.php
index 037a05d1dd..dd0a1ec878 100644
--- a/src/applications/phriction/editor/document/__init__.php
+++ b/src/applications/phriction/editor/document/__init__.php
@@ -1,22 +1,23 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/feed/constants/story');
 phutil_require_module('phabricator', 'applications/feed/publisher');
 phutil_require_module('phabricator', 'applications/phriction/constants/action');
 phutil_require_module('phabricator', 'applications/phriction/constants/changetype');
 phutil_require_module('phabricator', 'applications/phriction/constants/documentstatus');
 phutil_require_module('phabricator', 'applications/phriction/storage/content');
 phutil_require_module('phabricator', 'applications/phriction/storage/document');
 phutil_require_module('phabricator', 'applications/project/storage/project');
 phutil_require_module('phabricator', 'applications/search/index/indexer/phriction');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhrictionDocumentEditor.php');
diff --git a/src/applications/phriction/storage/document/PhrictionDocument.php b/src/applications/phriction/storage/document/PhrictionDocument.php
index 19f45fba9a..f71b5d8543 100644
--- a/src/applications/phriction/storage/document/PhrictionDocument.php
+++ b/src/applications/phriction/storage/document/PhrictionDocument.php
@@ -1,158 +1,102 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group phriction
  */
 final class PhrictionDocument extends PhrictionDAO {
 
   protected $id;
   protected $phid;
   protected $slug;
   protected $depth;
   protected $contentID;
   protected $status;
 
   private $contentObject;
 
   public function getConfiguration() {
     return array(
       self::CONFIG_AUX_PHID   => true,
       self::CONFIG_TIMESTAMPS => false,
     ) + parent::getConfiguration();
   }
 
   public function generatePHID() {
     return PhabricatorPHID::generateNewPHID(
       PhabricatorPHIDConstants::PHID_TYPE_WIKI);
   }
 
   public static function getSlugURI($slug, $type = 'document') {
     static $types = array(
       'document'  => '/w/',
       'history'   => '/phriction/history/',
     );
 
     if (empty($types[$type])) {
       throw new Exception("Unknown URI type '{$type}'!");
     }
 
     $prefix = $types[$type];
 
     if ($slug == '/') {
       return $prefix;
     } else {
       return $prefix.$slug;
     }
   }
 
-  public static function normalizeSlug($slug) {
-
-    // TODO: We need to deal with unicode at some point, this is just a very
-    // basic proof-of-concept implementation.
-
-    $slug = strtolower($slug);
-    $slug = preg_replace('@/+@', '/', $slug);
-    $slug = trim($slug, '/');
-    $slug = preg_replace('@[^a-z0-9/]+@', '_', $slug);
-    $slug = trim($slug, '_');
-
-    return $slug.'/';
-  }
-
-  public static function getDefaultSlugTitle($slug) {
-    $parts = explode('/', trim($slug, '/'));
-    $default_title = end($parts);
-    $default_title = str_replace('_', ' ', $default_title);
-    $default_title = ucwords($default_title);
-    $default_title = nonempty($default_title, 'Untitled Document');
-    return $default_title;
-  }
-
-  public static function getSlugAncestry($slug) {
-    $slug = self::normalizeSlug($slug);
-
-    if ($slug == '/') {
-      return array();
-    }
-
-    $ancestors = array(
-      '/',
-    );
-
-    $slug = explode('/', $slug);
-    array_pop($slug);
-    array_pop($slug);
-
-    $accumulate = '';
-    foreach ($slug as $part) {
-      $accumulate .= $part.'/';
-      $ancestors[] = $accumulate;
-    }
-
-    return $ancestors;
-  }
-
-  public static function getSlugDepth($slug) {
-    $slug = self::normalizeSlug($slug);
-    if ($slug == '/') {
-      return 0;
-    } else {
-      return substr_count($slug, '/');
-    }
-  }
-
   public function setSlug($slug) {
-    $this->slug   = self::normalizeSlug($slug);
-    $this->depth  = self::getSlugDepth($slug);
+    $this->slug   = PhabricatorSlug::normalize($slug);
+    $this->depth  = PhabricatorSlug::getDepth($slug);
     return $this;
   }
 
   public function attachContent(PhrictionContent $content) {
     $this->contentObject = $content;
     return $this;
   }
 
   public function getContent() {
     if (!$this->contentObject) {
       throw new Exception("Attach content with attachContent() first.");
     }
     return $this->contentObject;
   }
 
   public static function isProjectSlug($slug) {
-    $slug = self::normalizeSlug($slug);
+    $slug = PhabricatorSlug::normalize($slug);
     $prefix = 'projects/';
     if ($slug == $prefix) {
       // The 'projects/' document is not itself a project slug.
       return false;
     }
     return !strncmp($slug, $prefix, strlen($prefix));
   }
 
   public static function getProjectSlugIdentifier($slug) {
     if (!self::isProjectSlug($slug)) {
       throw new Exception("Slug '{$slug}' is not a project slug!");
     }
 
-    $slug = self::normalizeSlug($slug);
+    $slug = PhabricatorSlug::normalize($slug);
     $parts = explode('/', $slug);
     return $parts[1].'/';
   }
 
 }
diff --git a/src/applications/phriction/storage/document/__init__.php b/src/applications/phriction/storage/document/__init__.php
index f1fb50f9da..d7a9f2b287 100644
--- a/src/applications/phriction/storage/document/__init__.php
+++ b/src/applications/phriction/storage/document/__init__.php
@@ -1,16 +1,15 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/phid/constants');
 phutil_require_module('phabricator', 'applications/phid/storage/phid');
 phutil_require_module('phabricator', 'applications/phriction/storage/base');
-
-phutil_require_module('phutil', 'utils');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 
 
 phutil_require_source('PhrictionDocument.php');
diff --git a/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php b/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php
index 785c13439f..5bca5f230b 100644
--- a/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php
+++ b/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php
@@ -1,119 +1,67 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group phriction
  */
 final class PhrictionDocumentTestCase extends PhabricatorTestCase {
 
-  public function testSlugNormalization() {
-    $slugs = array(
-      ''                  => '/',
-      '/'                 => '/',
-      '//'                => '/',
-      '&&&'               => '/',
-      '/derp/'            => 'derp/',
-      'derp'              => 'derp/',
-      'derp//derp'        => 'derp/derp/',
-      'DERP//DERP'        => 'derp/derp/',
-      'a B c'             => 'a_b_c/',
-    );
-
-    foreach ($slugs as $slug => $normal) {
-      $this->assertEqual(
-        $normal,
-        PhrictionDocument::normalizeSlug($slug),
-        "Normalization of '{$slug}'");
-    }
-  }
-
-  public function testSlugAncestry() {
-    $slugs = array(
-      '/'                   => array(),
-      'pokemon/'            => array('/'),
-      'pokemon/squirtle/'   => array('/', 'pokemon/'),
-    );
-
-    foreach ($slugs as $slug => $ancestry) {
-      $this->assertEqual(
-        $ancestry,
-        PhrictionDocument::getSlugAncestry($slug),
-        "Ancestry of '{$slug}'");
-    }
-  }
-
-  public function testSlugDepth() {
-    $slugs = array(
-      '/'       => 0,
-      'a/'      => 1,
-      'a/b/'    => 2,
-      'a////b/' => 2,
-    );
-
-    foreach ($slugs as $slug => $depth) {
-      $this->assertEqual(
-        $depth,
-        PhrictionDocument::getSlugDepth($slug),
-        "Depth of '{$slug}'");
-    }
-  }
-
   public function testProjectSlugs() {
     $slugs = array(
       '/'                   => false,
       'zebra/'              => false,
       'projects/'           => false,
       'projects/a/'         => true,
       'projects/a/b/'       => true,
       'stuff/projects/a/'   => false,
     );
 
     foreach ($slugs as $slug => $expect) {
       $this->assertEqual(
         $expect,
         PhrictionDocument::isProjectSlug($slug),
         "Is '{$slug}' a project slug?");
     }
   }
 
   public function testProjectSlugIdentifiers() {
     $slugs = array(
       'projects/'     => null,
       'derp/'         => null,
       'projects/a/'   => 'a/',
       'projects/a/b/' => 'a/',
     );
 
     foreach ($slugs as $slug => $expect) {
       $ex = null;
       $result = null;
       try {
         $result = PhrictionDocument::getProjectSlugIdentifier($slug);
       } catch (Exception $e) {
         $ex = $e;
       }
 
       if ($expect === null) {
         $this->assertEqual(true, (bool)$ex, "Slug '{$slug}' is invalid.");
       } else {
         $this->assertEqual($expect, $result, "Slug '{$slug}' identifier.");
       }
     }
   }
 
 }
diff --git a/src/applications/project/controller/profile/PhabricatorProjectProfileController.php b/src/applications/project/controller/profile/PhabricatorProjectProfileController.php
index 07919ba71d..22c03f7a08 100644
--- a/src/applications/project/controller/profile/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/profile/PhabricatorProjectProfileController.php
@@ -1,381 +1,381 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 final class PhabricatorProjectProfileController
   extends PhabricatorProjectController {
 
   private $id;
   private $page;
 
   public function willProcessRequest(array $data) {
     $this->id = idx($data, 'id');
     $this->page = idx($data, 'page');
   }
 
   public function processRequest() {
     $request = $this->getRequest();
     $user = $request->getUser();
 
     $project = id(new PhabricatorProject())->load($this->id);
     if (!$project) {
       return new Aphront404Response();
     }
     $profile = $project->loadProfile();
     if (!$profile) {
       $profile = new PhabricatorProjectProfile();
     }
 
     $src_phid = $profile->getProfileImagePHID();
     if (!$src_phid) {
       $src_phid = $user->getProfileImagePHID();
     }
     $file = id(new PhabricatorFile())->loadOneWhere('phid = %s',
                                                     $src_phid);
     if ($file) {
       $picture = $file->getBestURI();
     } else {
       $picture = null;
     }
 
     $members = mpull($project->loadAffiliations(), null, 'getUserPHID');
 
     $nav_view = new AphrontSideNavFilterView();
     $uri = new PhutilURI('/project/view/'.$project->getID().'/');
     $nav_view->setBaseURI($uri);
 
     $external_arrow = "\xE2\x86\x97";
     $tasks_uri = '/maniphest/view/all/?projects='.$project->getPHID();
-    $slug = PhrictionDocument::normalizeSlug($project->getName());
+    $slug = PhabricatorSlug::normalize($project->getName());
     $phriction_uri = '/w/projects/'.$slug;
 
     $edit_uri = '/project/edit/'.$project->getID().'/';
 
     $nav_view->addFilter('dashboard', 'Dashboard');
     $nav_view->addSpacer();
     $nav_view->addFilter('feed', 'Feed');
     $nav_view->addFilter(null, 'Tasks '.$external_arrow, $tasks_uri);
     $nav_view->addFilter(null, 'Wiki '.$external_arrow, $phriction_uri);
     $nav_view->addFilter('people', 'People');
     $nav_view->addFilter('about', 'About');
     $nav_view->addSpacer();
     $nav_view->addFilter(null, "Edit Project\xE2\x80\xA6", $edit_uri);
 
     $this->page = $nav_view->selectFilter($this->page, 'dashboard');
 
 
     require_celerity_resource('phabricator-profile-css');
     switch ($this->page) {
       case 'dashboard':
         $content = $this->renderTasksPage($project, $profile);
 
         $query = new PhabricatorFeedQuery();
         $query->setFilterPHIDs(
           array(
             $project->getPHID(),
           ));
         $stories = $query->execute();
 
         $content .= $this->renderStories($stories);
         break;
       case 'about':
         $content = $this->renderAboutPage($project, $profile);
         break;
       case 'people':
         $content = $this->renderPeoplePage($project, $profile);
         break;
       case 'feed':
         $content = $this->renderFeedPage($project, $profile);
         break;
       default:
         throw new Exception("Unimplemented filter '{$this->page}'.");
     }
 
     $content = '<div style="padding: 1em;">'.$content.'</div>';
     $nav_view->appendChild($content);
 
     $header = new PhabricatorProfileHeaderView();
     $header->setName($project->getName());
     $header->setDescription(
       phutil_utf8_shorten($profile->getBlurb(), 1024));
     $header->setProfilePicture($picture);
 
     $action = null;
     if (empty($members[$user->getPHID()])) {
       $action = phabricator_render_form(
         $user,
         array(
           'action' => '/project/update/'.$project->getID().'/join/',
           'method' => 'post',
         ),
         phutil_render_tag(
           'button',
           array(
             'class' => 'green',
           ),
           'Join Project'));
     } else {
       $action = javelin_render_tag(
         'a',
         array(
           'href'  => '/project/update/'.$project->getID().'/leave/',
           'sigil' => 'workflow',
           'class' => 'grey button',
         ),
         'Leave Project...');
     }
 
     $header->addAction($action);
 
     $header->appendChild($nav_view);
 
     return $this->buildStandardPageResponse(
       $header,
       array(
         'title' => $project->getName().' Project',
       ));
   }
 
   private function renderAboutPage(
     PhabricatorProject $project,
     PhabricatorProjectProfile $profile) {
 
     $viewer = $this->getRequest()->getUser();
 
     $blurb = $profile->getBlurb();
     $blurb = phutil_escape_html($blurb);
     $blurb = str_replace("\n", '<br />', $blurb);
 
     $phids = array_merge(
       array($project->getAuthorPHID()),
       $project->getSubprojectPHIDs()
     );
     $phids = array_unique($phids);
     $handles = id(new PhabricatorObjectHandleData($phids))
       ->loadHandles();
 
     $timestamp = phabricator_datetime($project->getDateCreated(), $viewer);
 
     $about =
       '<div class="phabricator-profile-info-group">
         <h1 class="phabricator-profile-info-header">About</h1>
         <div class="phabricator-profile-info-pane">
           <table class="phabricator-profile-info-table">
             <tr>
               <th>Creator</th>
               <td>'.$handles[$project->getAuthorPHID()]->renderLink().'</td>
             </tr>
             <tr>
               <th>Created</th>
               <td>'.$timestamp.'</td>
             </tr>
             <tr>
               <th>PHID</th>
               <td>'.phutil_escape_html($project->getPHID()).'</td>
             </tr>
             <tr>
               <th>Blurb</th>
               <td>'.$blurb.'</td>
             </tr>
           </table>
         </div>
       </div>';
 
     if ($project->getSubprojectPHIDs()) {
       $table = $this->renderSubprojectTable(
         $handles,
         $project->getSubprojectPHIDs());
       $subproject_list = $table->render();
     } else {
       $subproject_list = '<p><em>No subprojects.</em></p>';
     }
 
     $about .=
       '<div class="phabricator-profile-info-group">'.
         '<h1 class="phabricator-profile-info-header">Subprojects</h1>'.
         '<div class="phabricator-profile-info-pane">'.
           $subproject_list.
         '</div>'.
       '</div>';
 
     return $about;
   }
 
   private function renderPeoplePage(
     PhabricatorProject $project,
     PhabricatorProjectProfile $profile) {
 
     $affiliations = $project->loadAffiliations();
 
     $phids = mpull($affiliations, 'getUserPHID');
     $handles = id(new PhabricatorObjectHandleData($phids))
       ->loadHandles();
 
     $affiliated = array();
     foreach ($affiliations as $affiliation) {
       $user = $handles[$affiliation->getUserPHID()]->renderLink();
       $role = phutil_escape_html($affiliation->getRole());
       $affiliated[] = '<li>'.$user.' &mdash; '.$role.'</li>';
     }
 
     if ($affiliated) {
       $affiliated = '<ul>'.implode("\n", $affiliated).'</ul>';
     } else {
       $affiliated = '<p><em>No one is affiliated with this project.</em></p>';
     }
 
     return
       '<div class="phabricator-profile-info-group">'.
         '<h1 class="phabricator-profile-info-header">People</h1>'.
         '<div class="phabricator-profile-info-pane">'.
          $affiliated.
         '</div>'.
       '</div>';
   }
 
   private function renderFeedPage(
     PhabricatorProject $project,
     PhabricatorProjectProfile $profile) {
 
     $query = new PhabricatorFeedQuery();
     $query->setFilterPHIDs(array($project->getPHID()));
     $stories = $query->execute();
 
     if (!$stories) {
       return 'There are no stories about this project.';
     }
 
     $query = new PhabricatorFeedQuery();
     $query->setFilterPHIDs(
       array(
         $project->getPHID(),
       ));
     $stories = $query->execute();
 
     return $this->renderStories($stories);
   }
 
   private function renderStories(array $stories) {
     assert_instances_of($stories, 'PhabricatorFeedStory');
 
     $builder = new PhabricatorFeedBuilder($stories);
     $builder->setUser($this->getRequest()->getUser());
     $view = $builder->buildView();
 
     return
       '<div class="phabricator-profile-info-group">'.
         '<h1 class="phabricator-profile-info-header">Activity Feed</h1>'.
         '<div class="phabricator-profile-info-pane">'.
          $view->render().
         '</div>'.
       '</div>';
   }
 
 
   private function renderTasksPage(
     PhabricatorProject $project,
     PhabricatorProjectProfile $profile) {
 
     $query = id(new ManiphestTaskQuery())
       ->withProjects(array($project->getPHID()))
       ->withStatus(ManiphestTaskQuery::STATUS_OPEN)
       ->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY)
       ->setLimit(10)
       ->setCalculateRows(true);
     $tasks = $query->execute();
     $count = $query->getRowCount();
 
     $phids = mpull($tasks, 'getOwnerPHID');
     $phids = array_filter($phids);
     $handles = id(new PhabricatorObjectHandleData($phids))
       ->loadHandles();
 
     $task_views = array();
     foreach ($tasks as $task) {
       $view = id(new ManiphestTaskSummaryView())
         ->setTask($task)
         ->setHandles($handles)
         ->setUser($this->getRequest()->getUser());
       $task_views[] = $view->render();
     }
 
     if (empty($tasks)) {
       $task_views = '<em>No open tasks.</em>';
     } else {
       $task_views = implode('', $task_views);
     }
 
     $open = number_format($count);
 
     $more_link = phutil_render_tag(
       'a',
       array(
         'href' => '/maniphest/view/all/?projects='.$project->getPHID(),
       ),
       "View All Open Tasks \xC2\xBB");
 
     $content =
       '<div class="phabricator-profile-info-group">
         <h1 class="phabricator-profile-info-header">'.
           "Open Tasks ({$open})".
         '</h1>'.
         '<div class="phabricator-profile-info-pane">'.
           $task_views.
           '<div class="phabricator-profile-info-pane-more-link">'.
             $more_link.
           '</div>'.
         '</div>
       </div>';
 
     return $content;
   }
 
   private function renderSubprojectTable(
     PhabricatorObjectHandleData $handles,
     $subprojects_phids) {
 
     $rows = array();
     foreach ($subprojects_phids as $subproject_phid) {
       $phid = $handles[$subproject_phid]->getPHID();
 
       $rows[] = array(
         phutil_escape_html($handles[$phid]->getFullName()),
         phutil_render_tag(
           'a',
           array(
             'class' => 'small grey button',
             'href' => $handles[$phid]->getURI(),
           ),
           'View Project Profile'),
       );
     }
 
     $table = new AphrontTableView($rows);
      $table->setHeaders(
        array(
          'Name',
          '',
        ));
      $table->setColumnClasses(
        array(
          'pri',
          'action right',
        ));
 
     return $table;
   }
 }
diff --git a/src/applications/project/controller/profile/__init__.php b/src/applications/project/controller/profile/__init__.php
index 0d4a5a51d9..8447952294 100644
--- a/src/applications/project/controller/profile/__init__.php
+++ b/src/applications/project/controller/profile/__init__.php
@@ -1,32 +1,32 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'aphront/response/404');
 phutil_require_module('phabricator', 'applications/feed/builder/feed');
 phutil_require_module('phabricator', 'applications/feed/query');
 phutil_require_module('phabricator', 'applications/files/storage/file');
 phutil_require_module('phabricator', 'applications/maniphest/query');
 phutil_require_module('phabricator', 'applications/maniphest/view/tasksummary');
 phutil_require_module('phabricator', 'applications/phid/handle/data');
-phutil_require_module('phabricator', 'applications/phriction/storage/document');
 phutil_require_module('phabricator', 'applications/project/controller/base');
 phutil_require_module('phabricator', 'applications/project/storage/profile');
 phutil_require_module('phabricator', 'applications/project/storage/project');
 phutil_require_module('phabricator', 'infrastructure/celerity/api');
 phutil_require_module('phabricator', 'infrastructure/javelin/markup');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 phutil_require_module('phabricator', 'view/control/table');
 phutil_require_module('phabricator', 'view/layout/profileheader');
 phutil_require_module('phabricator', 'view/layout/sidenavfilter');
 phutil_require_module('phabricator', 'view/utils');
 
 phutil_require_module('phutil', 'markup');
 phutil_require_module('phutil', 'parser/uri');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhabricatorProjectProfileController.php');
diff --git a/src/applications/project/storage/project/PhabricatorProject.php b/src/applications/project/storage/project/PhabricatorProject.php
index 429558cafc..c279d0a953 100644
--- a/src/applications/project/storage/project/PhabricatorProject.php
+++ b/src/applications/project/storage/project/PhabricatorProject.php
@@ -1,103 +1,103 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 final class PhabricatorProject extends PhabricatorProjectDAO {
 
   protected $name;
   protected $phid;
   protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
   protected $authorPHID;
   protected $subprojectPHIDs = array();
   protected $phrictionSlug;
 
   private $subprojectsNeedUpdate;
   private $affiliations;
 
   public function getConfiguration() {
     return array(
       self::CONFIG_AUX_PHID => true,
       self::CONFIG_SERIALIZATION => array(
         'subprojectPHIDs' => self::SERIALIZATION_JSON,
       ),
     ) + parent::getConfiguration();
   }
 
   public function generatePHID() {
     return PhabricatorPHID::generateNewPHID(
       PhabricatorPHIDConstants::PHID_TYPE_PROJ);
   }
 
   public function setSubprojectPHIDs(array $phids) {
     $this->subprojectPHIDs = $phids;
     $this->subprojectsNeedUpdate = true;
     return $this;
   }
 
   public function loadProfile() {
     $profile = id(new PhabricatorProjectProfile())->loadOneWhere(
       'projectPHID = %s',
       $this->getPHID());
     return $profile;
   }
 
   public function getAffiliations() {
     if ($this->affiliations === null) {
       throw new Exception('Attach affiliations first!');
     }
     return $this->affiliations;
   }
 
   public function attachAffiliations(array $affiliations) {
     assert_instances_of($affiliations, 'PhabricatorProjectAffiliation');
     $this->affiliations = $affiliations;
     return $this;
   }
 
   public function loadAffiliations() {
     $affils = PhabricatorProjectAffiliation::loadAllForProjectPHIDs(
       array($this->getPHID()));
     return $affils[$this->getPHID()];
   }
 
   public function setPhrictionSlug($slug) {
 
     // NOTE: We're doing a little magic here and stripping out '/' so that
     // project pages always appear at top level under projects/ even if the
     // display name is "Hack / Slash" or similar (it will become
     // 'hack_slash' instead of 'hack/slash').
 
     $slug = str_replace('/', ' ', $slug);
-    $slug = PhrictionDocument::normalizeSlug($slug);
+    $slug = PhabricatorSlug::normalize($slug);
     $this->phrictionSlug = $slug;
     return $this;
   }
 
   public function save() {
     $result = parent::save();
 
     if ($this->subprojectsNeedUpdate) {
       // If we've changed the project PHIDs for this task, update the link
       // table.
       PhabricatorProjectSubproject::updateProjectSubproject($this);
       $this->subprojectsNeedUpdate = false;
     }
 
     return $result;
   }
 
 }
diff --git a/src/applications/project/storage/project/__init__.php b/src/applications/project/storage/project/__init__.php
index 5f0638b4fb..f567560ad8 100644
--- a/src/applications/project/storage/project/__init__.php
+++ b/src/applications/project/storage/project/__init__.php
@@ -1,21 +1,21 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/phid/constants');
 phutil_require_module('phabricator', 'applications/phid/storage/phid');
-phutil_require_module('phabricator', 'applications/phriction/storage/document');
 phutil_require_module('phabricator', 'applications/project/constants/status');
 phutil_require_module('phabricator', 'applications/project/storage/affiliation');
 phutil_require_module('phabricator', 'applications/project/storage/base');
 phutil_require_module('phabricator', 'applications/project/storage/profile');
 phutil_require_module('phabricator', 'applications/project/storage/subproject');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhabricatorProject.php');
diff --git a/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php b/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php
index b7ae8ba003..718e50554c 100644
--- a/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php
+++ b/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php
@@ -1,52 +1,52 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group markup
  */
 final class PhabricatorRemarkupRulePhriction
   extends PhutilRemarkupRule {
 
   public function apply($text) {
     return preg_replace_callback(
       '@\B\\[\\[([^|\\]]+)(?:\\|([^\\]]+))?\\]\\]\B@U',
       array($this, 'markupDocumentLink'),
       $text);
   }
 
   public function markupDocumentLink($matches) {
 
     $slug = trim($matches[1]);
     $name = trim(idx($matches, 2, $slug));
     $name = explode('/', trim($name, '/'));
     $name = end($name);
 
-    $slug = PhrictionDocument::normalizeSlug($slug);
+    $slug = PhabricatorSlug::normalize($slug);
     $uri  = PhrictionDocument::getSlugURI($slug);
 
     return $this->getEngine()->storeText(
       phutil_render_tag(
         'a',
         array(
           'href'  => $uri,
           'class' => 'phriction-link',
         ),
         phutil_escape_html($name)));
   }
 
 }
diff --git a/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php b/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php
index 1c70aaadfc..817f28a35f 100644
--- a/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php
+++ b/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php
@@ -1,16 +1,17 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/phriction/storage/document');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
 
 phutil_require_module('phutil', 'markup');
 phutil_require_module('phutil', 'markup/engine/remarkup/markuprule/base');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('PhabricatorRemarkupRulePhriction.php');
diff --git a/src/infrastructure/util/slug/PhabricatorSlug.php b/src/infrastructure/util/slug/PhabricatorSlug.php
new file mode 100644
index 0000000000..9ed0938898
--- /dev/null
+++ b/src/infrastructure/util/slug/PhabricatorSlug.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+final class PhabricatorSlug {
+
+  public static function normalize($slug) {
+
+    // TODO: We need to deal with unicode at some point, this is just a very
+    // basic proof-of-concept implementation.
+
+    $slug = strtolower($slug);
+    $slug = preg_replace('@/+@', '/', $slug);
+    $slug = trim($slug, '/');
+    $slug = preg_replace('@[^a-z0-9/]+@', '_', $slug);
+    $slug = trim($slug, '_');
+
+    return $slug.'/';
+  }
+
+  public static function getDefaultTitle($slug) {
+    $parts = explode('/', trim($slug, '/'));
+    $default_title = end($parts);
+    $default_title = str_replace('_', ' ', $default_title);
+    $default_title = ucwords($default_title);
+    $default_title = nonempty($default_title, 'Untitled Document');
+    return $default_title;
+  }
+
+  public static function getAncestry($slug) {
+    $slug = self::normalize($slug);
+
+    if ($slug == '/') {
+      return array();
+    }
+
+    $ancestors = array(
+      '/',
+    );
+
+    $slug = explode('/', $slug);
+    array_pop($slug);
+    array_pop($slug);
+
+    $accumulate = '';
+    foreach ($slug as $part) {
+      $accumulate .= $part.'/';
+      $ancestors[] = $accumulate;
+    }
+
+    return $ancestors;
+  }
+
+  public static function getDepth($slug) {
+    $slug = self::normalize($slug);
+    if ($slug == '/') {
+      return 0;
+    } else {
+      return substr_count($slug, '/');
+    }
+  }
+
+}
diff --git a/src/infrastructure/util/slug/__init__.php b/src/infrastructure/util/slug/__init__.php
new file mode 100644
index 0000000000..bace58f54b
--- /dev/null
+++ b/src/infrastructure/util/slug/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorSlug.php');
diff --git a/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php b/src/infrastructure/util/slug/__tests__/PhabricatorSlugTestCase.php
similarity index 56%
copy from src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php
copy to src/infrastructure/util/slug/__tests__/PhabricatorSlugTestCase.php
index 785c13439f..79f388d5ca 100644
--- a/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php
+++ b/src/infrastructure/util/slug/__tests__/PhabricatorSlugTestCase.php
@@ -1,119 +1,74 @@
 <?php
 
 /*
  * Copyright 2012 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-/**
- * @group phriction
- */
-final class PhrictionDocumentTestCase extends PhabricatorTestCase {
+final class PhabricatorSlugTestCase extends PhabricatorTestCase {
 
   public function testSlugNormalization() {
     $slugs = array(
       ''                  => '/',
       '/'                 => '/',
       '//'                => '/',
       '&&&'               => '/',
       '/derp/'            => 'derp/',
       'derp'              => 'derp/',
       'derp//derp'        => 'derp/derp/',
       'DERP//DERP'        => 'derp/derp/',
       'a B c'             => 'a_b_c/',
+      '-1~2.3abcd'        => '1_2_3abcd/',
+      "T\x95O\x95D\x95O"  => 't_o_d_o/',
     );
 
     foreach ($slugs as $slug => $normal) {
       $this->assertEqual(
         $normal,
-        PhrictionDocument::normalizeSlug($slug),
+        PhabricatorSlug::normalize($slug),
         "Normalization of '{$slug}'");
     }
   }
 
   public function testSlugAncestry() {
     $slugs = array(
       '/'                   => array(),
       'pokemon/'            => array('/'),
       'pokemon/squirtle/'   => array('/', 'pokemon/'),
     );
 
     foreach ($slugs as $slug => $ancestry) {
       $this->assertEqual(
         $ancestry,
-        PhrictionDocument::getSlugAncestry($slug),
+        PhabricatorSlug::getAncestry($slug),
         "Ancestry of '{$slug}'");
     }
   }
 
   public function testSlugDepth() {
     $slugs = array(
       '/'       => 0,
       'a/'      => 1,
       'a/b/'    => 2,
       'a////b/' => 2,
     );
 
     foreach ($slugs as $slug => $depth) {
       $this->assertEqual(
         $depth,
-        PhrictionDocument::getSlugDepth($slug),
+        PhabricatorSlug::getDepth($slug),
         "Depth of '{$slug}'");
     }
   }
-
-  public function testProjectSlugs() {
-    $slugs = array(
-      '/'                   => false,
-      'zebra/'              => false,
-      'projects/'           => false,
-      'projects/a/'         => true,
-      'projects/a/b/'       => true,
-      'stuff/projects/a/'   => false,
-    );
-
-    foreach ($slugs as $slug => $expect) {
-      $this->assertEqual(
-        $expect,
-        PhrictionDocument::isProjectSlug($slug),
-        "Is '{$slug}' a project slug?");
-    }
-  }
-
-  public function testProjectSlugIdentifiers() {
-    $slugs = array(
-      'projects/'     => null,
-      'derp/'         => null,
-      'projects/a/'   => 'a/',
-      'projects/a/b/' => 'a/',
-    );
-
-    foreach ($slugs as $slug => $expect) {
-      $ex = null;
-      $result = null;
-      try {
-        $result = PhrictionDocument::getProjectSlugIdentifier($slug);
-      } catch (Exception $e) {
-        $ex = $e;
-      }
-
-      if ($expect === null) {
-        $this->assertEqual(true, (bool)$ex, "Slug '{$slug}' is invalid.");
-      } else {
-        $this->assertEqual($expect, $result, "Slug '{$slug}' identifier.");
-      }
-    }
-  }
-
 }
diff --git a/src/infrastructure/util/slug/__tests__/__init__.php b/src/infrastructure/util/slug/__tests__/__init__.php
new file mode 100644
index 0000000000..773469f886
--- /dev/null
+++ b/src/infrastructure/util/slug/__tests__/__init__.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'infrastructure/testing/testcase');
+phutil_require_module('phabricator', 'infrastructure/util/slug');
+
+
+phutil_require_source('PhabricatorSlugTestCase.php');