diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 1aded6c0a..458b0a6ee 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,831 +1,833 @@
 <?php
 
 /**
  * This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
  * @generated
  */
 
 phutil_register_library_map(array(
   'class' =>
   array(
     'Aphront400Response' => 'aphront/response/400',
     'Aphront404Response' => 'aphront/response/404',
     'AphrontAjaxResponse' => 'aphront/response/ajax',
     'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
     'AphrontController' => 'aphront/controller',
     'AphrontCrumbsView' => 'view/layout/crumbs',
     'AphrontDatabaseConnection' => 'storage/connection/base',
     'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
     'AphrontDefaultApplicationController' => 'aphront/default/controller',
     'AphrontDialogResponse' => 'aphront/response/dialog',
     'AphrontDialogView' => 'view/dialog',
     'AphrontErrorView' => 'view/form/error',
     'AphrontException' => 'aphront/exception/base',
     'AphrontFileResponse' => 'aphront/response/file',
     'AphrontFormCheckboxControl' => 'view/form/control/checkbox',
     'AphrontFormControl' => 'view/form/control/base',
     'AphrontFormDividerControl' => 'view/form/control/divider',
     'AphrontFormFileControl' => 'view/form/control/file',
     'AphrontFormMarkupControl' => 'view/form/control/markup',
     'AphrontFormPasswordControl' => 'view/form/control/password',
     'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha',
     'AphrontFormSelectControl' => 'view/form/control/select',
     'AphrontFormStaticControl' => 'view/form/control/static',
     'AphrontFormSubmitControl' => 'view/form/control/submit',
     'AphrontFormTextAreaControl' => 'view/form/control/textarea',
     'AphrontFormTextControl' => 'view/form/control/text',
     'AphrontFormToggleButtonsControl' => 'view/form/control/togglebuttons',
     'AphrontFormTokenizerControl' => 'view/form/control/tokenizer',
     'AphrontFormView' => 'view/form/base',
     'AphrontHeadsupActionListView' => 'view/layout/headsup/actionlist',
     'AphrontHeadsupActionView' => 'view/layout/headsup/action',
     'AphrontListFilterView' => 'view/layout/listfilter',
     'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql',
     'AphrontNullView' => 'view/null',
     'AphrontPageView' => 'view/page/base',
     'AphrontPagerView' => 'view/control/pager',
     'AphrontPanelView' => 'view/layout/panel',
     'AphrontQueryConnectionException' => 'storage/exception/connection',
     'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost',
     'AphrontQueryCountException' => 'storage/exception/count',
     'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey',
     'AphrontQueryException' => 'storage/exception/base',
     'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing',
     'AphrontQueryParameterException' => 'storage/exception/parameter',
     'AphrontQueryRecoverableException' => 'storage/exception/recoverable',
     'AphrontRedirectException' => 'aphront/exception/redirect',
     'AphrontRedirectResponse' => 'aphront/response/redirect',
     'AphrontRequest' => 'aphront/request',
     'AphrontRequestFailureView' => 'view/page/failure',
     'AphrontResponse' => 'aphront/response/base',
     'AphrontSideNavView' => 'view/layout/sidenav',
     'AphrontTableView' => 'view/control/table',
     'AphrontTokenizerTemplateView' => 'view/control/tokenizer',
     'AphrontTypeaheadTemplateView' => 'view/control/typeahead',
     'AphrontURIMapper' => 'aphront/mapper',
     'AphrontView' => 'view/base',
     'AphrontWebpageResponse' => 'aphront/response/webpage',
     'CelerityAPI' => 'infrastructure/celerity/api',
     'CelerityResourceController' => 'infrastructure/celerity/controller',
     'CelerityResourceMap' => 'infrastructure/celerity/map',
     'CelerityStaticResourceResponse' => 'infrastructure/celerity/response',
     'ConduitAPIMethod' => 'applications/conduit/method/base',
     'ConduitAPIRequest' => 'applications/conduit/protocol/request',
     'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect',
     'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping',
     'ConduitAPI_daemon_launched_Method' => 'applications/conduit/method/daemon/launched',
     'ConduitAPI_daemon_log_Method' => 'applications/conduit/method/daemon/log',
     'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff',
     'ConduitAPI_differential_createrevision_Method' => 'applications/conduit/method/differential/createrevision',
     'ConduitAPI_differential_find_Method' => 'applications/conduit/method/differential/find',
     'ConduitAPI_differential_getalldiffs_Method' => 'applications/conduit/method/differential/getalldiffs',
     'ConduitAPI_differential_getcommitmessage_Method' => 'applications/conduit/method/differential/getcommitmessage',
     'ConduitAPI_differential_getcommitpaths_Method' => 'applications/conduit/method/differential/getcommitpaths',
     'ConduitAPI_differential_getdiff_Method' => 'applications/conduit/method/differential/getdiff',
     'ConduitAPI_differential_getrevision_Method' => 'applications/conduit/method/differential/getrevision',
     'ConduitAPI_differential_getrevisionfeedback_Method' => 'applications/conduit/method/differential/getrevisionfeedback',
     'ConduitAPI_differential_markcommitted_Method' => 'applications/conduit/method/differential/markcommitted',
     'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/conduit/method/differential/parsecommitmessage',
     'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty',
     'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision',
+    'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'applications/conduit/method/differential/updatetaskrevisionassoc',
     'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits',
     'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
     'ConduitAPI_path_getowners_Method' => 'applications/conduit/method/path/getowners',
     'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
     'ConduitAPI_user_whoami_Method' => 'applications/conduit/method/user/whoami',
     'ConduitException' => 'applications/conduit/protocol/exception',
     'DarkConsole' => 'aphront/console/api',
     'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
     'DarkConsoleController' => 'aphront/console/controller',
     'DarkConsoleCore' => 'aphront/console/core',
     'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog',
     'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api',
     'DarkConsolePlugin' => 'aphront/console/plugin/base',
     'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request',
     'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services',
     'DarkConsoleServicesPluginAPI' => 'aphront/console/plugin/services/api',
     'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof',
     'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api',
     'DifferentialAction' => 'applications/differential/constants/action',
     'DifferentialAddCommentView' => 'applications/differential/view/addcomment',
     'DifferentialAttachController' => 'applications/differential/controller/attach',
     'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
     'DifferentialChangeType' => 'applications/differential/constants/changetype',
     'DifferentialChangeset' => 'applications/differential/storage/changeset',
     'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview',
     'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview',
     'DifferentialChangesetParser' => 'applications/differential/parser/changeset',
     'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview',
     'DifferentialComment' => 'applications/differential/storage/comment',
     'DifferentialCommentEditor' => 'applications/differential/editor/comment',
     'DifferentialCommentMail' => 'applications/differential/mail/comment',
     'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview',
     'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave',
     'DifferentialCommitMessage' => 'applications/differential/parser/commitmessage',
     'DifferentialCommitMessageData' => 'applications/differential/data/commitmessage',
     'DifferentialCommitMessageParserException' => 'applications/differential/parser/commitmessage/exception',
     'DifferentialController' => 'applications/differential/controller/base',
     'DifferentialDAO' => 'applications/differential/storage/base',
     'DifferentialDiff' => 'applications/differential/storage/diff',
     'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent',
     'DifferentialDiffCreateController' => 'applications/differential/controller/diffcreate',
     'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty',
     'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
     'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
     'DifferentialHunk' => 'applications/differential/storage/hunk',
     'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment',
     'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit',
     'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview',
     'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment',
     'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
     'DifferentialMail' => 'applications/differential/mail/base',
     'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup',
     'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff',
     'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
     'DifferentialRevision' => 'applications/differential/storage/revision',
     'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist',
     'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment',
     'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem',
     'DifferentialRevisionDetailRenderer' => 'applications/differential/controller/customrenderer',
     'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail',
     'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit',
     'DifferentialRevisionEditor' => 'applications/differential/editor/revision',
     'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
     'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
     'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
     'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
     'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
     'DifferentialSubscribeController' => 'applications/differential/controller/subscribe',
     'DifferentialTasksAttacher' => 'applications/differential/tasks',
     'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
     'DifferentialViewTime' => 'applications/differential/storage/viewtime',
     'DiffusionBranchInformation' => 'applications/diffusion/data/branch',
     'DiffusionBranchQuery' => 'applications/diffusion/query/branch/base',
     'DiffusionBranchTableView' => 'applications/diffusion/view/branchtable',
     'DiffusionBrowseController' => 'applications/diffusion/controller/browse',
     'DiffusionBrowseFileController' => 'applications/diffusion/controller/file',
     'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base',
     'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable',
     'DiffusionChangeController' => 'applications/diffusion/controller/change',
     'DiffusionCommitChangeTableView' => 'applications/diffusion/view/commitchangetable',
     'DiffusionCommitController' => 'applications/diffusion/controller/commit',
     'DiffusionController' => 'applications/diffusion/controller/base',
     'DiffusionDiffController' => 'applications/diffusion/controller/diff',
     'DiffusionDiffQuery' => 'applications/diffusion/query/diff/base',
     'DiffusionFileContent' => 'applications/diffusion/data/filecontent',
     'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base',
     'DiffusionGitBranchQuery' => 'applications/diffusion/query/branch/git',
     'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git',
     'DiffusionGitDiffQuery' => 'applications/diffusion/query/diff/git',
     'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/git',
     'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/git',
     'DiffusionGitLastModifiedQuery' => 'applications/diffusion/query/lastmodified/git',
     'DiffusionGitPathIDQuery' => 'applications/diffusion/query/pathid/base',
     'DiffusionGitRequest' => 'applications/diffusion/request/git',
     'DiffusionHistoryController' => 'applications/diffusion/controller/history',
     'DiffusionHistoryQuery' => 'applications/diffusion/query/history/base',
     'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable',
     'DiffusionHomeController' => 'applications/diffusion/controller/home',
     'DiffusionLastModifiedController' => 'applications/diffusion/controller/lastmodified',
     'DiffusionLastModifiedQuery' => 'applications/diffusion/query/lastmodified/base',
     'DiffusionPathChange' => 'applications/diffusion/data/pathchange',
     'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/base',
     'DiffusionPathCompleteController' => 'applications/diffusion/controller/pathcomplete',
     'DiffusionPathValidateController' => 'applications/diffusion/controller/pathvalidate',
     'DiffusionRepositoryController' => 'applications/diffusion/controller/repository',
     'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath',
     'DiffusionRequest' => 'applications/diffusion/request/base',
     'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/svn',
     'DiffusionSvnDiffQuery' => 'applications/diffusion/query/diff/svn',
     'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/svn',
     'DiffusionSvnHistoryQuery' => 'applications/diffusion/query/history/svn',
     'DiffusionSvnLastModifiedQuery' => 'applications/diffusion/query/lastmodified/svn',
     'DiffusionSvnRequest' => 'applications/diffusion/request/svn',
     'DiffusionView' => 'applications/diffusion/view/base',
     'HeraldAction' => 'applications/herald/storage/action',
     'HeraldActionConfig' => 'applications/herald/config/action',
     'HeraldApplyTranscript' => 'applications/herald/storage/transcript/apply',
     'HeraldCommitAdapter' => 'applications/herald/adapter/commit',
     'HeraldCondition' => 'applications/herald/storage/condition',
     'HeraldConditionConfig' => 'applications/herald/config/condition',
     'HeraldConditionTranscript' => 'applications/herald/storage/transcript/condition',
     'HeraldContentTypeConfig' => 'applications/herald/config/contenttype',
     'HeraldController' => 'applications/herald/controller/base',
     'HeraldDAO' => 'applications/herald/storage/base',
     'HeraldDeleteController' => 'applications/herald/controller/delete',
     'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/differential',
     'HeraldDryRunAdapter' => 'applications/herald/adapter/dryrun',
     'HeraldEffect' => 'applications/herald/engine/effect',
     'HeraldEngine' => 'applications/herald/engine/engine',
     'HeraldFieldConfig' => 'applications/herald/config/field',
     'HeraldHomeController' => 'applications/herald/controller/home',
     'HeraldInvalidConditionException' => 'applications/herald/engine/engine/exception',
     'HeraldInvalidFieldException' => 'applications/herald/engine/engine/exception',
     'HeraldNewController' => 'applications/herald/controller/new',
     'HeraldObjectAdapter' => 'applications/herald/adapter/base',
     'HeraldObjectTranscript' => 'applications/herald/storage/transcript/object',
     'HeraldRecursiveConditionsException' => 'applications/herald/engine/engine/exception',
     'HeraldRule' => 'applications/herald/storage/rule',
     'HeraldRuleController' => 'applications/herald/controller/rule',
     'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule',
     'HeraldTestConsoleController' => 'applications/herald/controller/test',
     'HeraldTranscript' => 'applications/herald/storage/transcript/base',
     'HeraldTranscriptController' => 'applications/herald/controller/transcript',
     'HeraldTranscriptListController' => 'applications/herald/controller/transcriptlist',
     'HeraldValueTypeConfig' => 'applications/herald/config/valuetype',
     'Javelin' => 'infrastructure/javelin/api',
     'LiskDAO' => 'storage/lisk/dao',
     'ManiphestController' => 'applications/maniphest/controller/base',
     'ManiphestDAO' => 'applications/maniphest/storage/base',
     'ManiphestTask' => 'applications/maniphest/storage/task',
     'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail',
     'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit',
     'ManiphestTaskListController' => 'applications/maniphest/controller/tasklist',
     'ManiphestTaskListView' => 'applications/maniphest/view/tasklist',
     'ManiphestTaskPriority' => 'applications/maniphest/constants/priority',
     'ManiphestTaskSelectorSearchController' => 'applications/maniphest/controller/taskselectorsearch',
     'ManiphestTaskStatus' => 'applications/maniphest/constants/status',
     'ManiphestTaskSummaryView' => 'applications/maniphest/view/tasksummary',
     'ManiphestTransaction' => 'applications/maniphest/storage/transaction',
     'ManiphestTransactionDetailView' => 'applications/maniphest/view/transactiondetail',
     'ManiphestTransactionEditor' => 'applications/maniphest/editor/transaction',
     'ManiphestTransactionListView' => 'applications/maniphest/view/transactionlist',
     'ManiphestTransactionSaveController' => 'applications/maniphest/controller/transactionsave',
     'ManiphestTransactionType' => 'applications/maniphest/constants/transactiontype',
     'Phabricator404Controller' => 'applications/base/controller/404',
     'PhabricatorAuthController' => 'applications/auth/controller/base',
     'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
     'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
     'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console',
     'PhabricatorConduitController' => 'applications/conduit/controller/base',
     'PhabricatorConduitDAO' => 'applications/conduit/storage/base',
     'PhabricatorConduitLogController' => 'applications/conduit/controller/log',
     'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog',
     'PhabricatorController' => 'applications/base/controller/base',
     'PhabricatorDaemon' => 'infrastructure/daemon/base',
     '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',
     'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/logview',
     'PhabricatorDaemonReference' => 'infrastructure/daemon/control/reference',
     'PhabricatorDaemonTimelineConsoleController' => 'applications/daemon/controller/timeline',
     'PhabricatorDaemonTimelineEventController' => 'applications/daemon/controller/timelineevent',
     'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
     'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
     'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
     'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist',
     'PhabricatorDirectoryController' => 'applications/directory/controller/base',
     'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
     'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
     'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
     'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
     'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist',
     'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
     'PhabricatorDraft' => 'applications/draft/storage/draft',
     'PhabricatorDraftDAO' => 'applications/draft/storage/base',
     'PhabricatorEditPreferencesController' => 'applications/preferences/controller/edit',
     'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
     'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
     'PhabricatorEnv' => 'infrastructure/env',
     'PhabricatorFile' => 'applications/files/storage/file',
     'PhabricatorFileController' => 'applications/files/controller/base',
     'PhabricatorFileDAO' => 'applications/files/storage/base',
     'PhabricatorFileImageMacro' => 'applications/files/storage/imagemacro',
     'PhabricatorFileListController' => 'applications/files/controller/list',
     'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob',
     'PhabricatorFileURI' => 'applications/files/uri',
     'PhabricatorFileUploadController' => 'applications/files/controller/upload',
     'PhabricatorFileViewController' => 'applications/files/controller/view',
     'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing',
     'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector',
     'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
     'PhabricatorLoginController' => 'applications/auth/controller/login',
     'PhabricatorLogoutController' => 'applications/auth/controller/logout',
     'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
     'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
     'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
     'PhabricatorMetaMTADaemon' => 'applications/metamta/daemon/mta',
     'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list',
     'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail',
     'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist',
     'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit',
     'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists',
     'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send',
     'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view',
     'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/default',
     'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/oauthdiagnostics',
     'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure',
     'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth',
     'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base',
     'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook',
     'PhabricatorOAuthProviderGithub' => 'applications/auth/oauth/provider/github',
     'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base',
     'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink',
     'PhabricatorObjectHandle' => 'applications/phid/handle',
     'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
     'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
     'PhabricatorOwnersController' => 'applications/owners/controller/base',
     'PhabricatorOwnersDAO' => 'applications/owners/storage/base',
     'PhabricatorOwnersDeleteController' => 'applications/owners/controller/delete',
     'PhabricatorOwnersDetailController' => 'applications/owners/controller/detail',
     'PhabricatorOwnersEditController' => 'applications/owners/controller/edit',
     'PhabricatorOwnersListController' => 'applications/owners/controller/list',
     'PhabricatorOwnersOwner' => 'applications/owners/storage/owner',
     'PhabricatorOwnersPackage' => 'applications/owners/storage/package',
     'PhabricatorOwnersPath' => 'applications/owners/storage/path',
     'PhabricatorPHID' => 'applications/phid/storage/phid',
     'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate',
     'PhabricatorPHIDConstants' => 'applications/phid/constants',
     'PhabricatorPHIDController' => 'applications/phid/controller/base',
     'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
     'PhabricatorPHIDListController' => 'applications/phid/controller/list',
     'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup',
     'PhabricatorPeopleController' => 'applications/people/controller/base',
     'PhabricatorPeopleEditController' => 'applications/people/controller/edit',
     'PhabricatorPeopleListController' => 'applications/people/controller/list',
     'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
     'PhabricatorPeopleProfileEditController' => 'applications/people/controller/profileedit',
     'PhabricatorPreferencesController' => 'applications/preferences/controller/base',
     'PhabricatorProject' => 'applications/project/storage/project',
     'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
     'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
     'PhabricatorProjectController' => 'applications/project/controller/base',
     'PhabricatorProjectDAO' => 'applications/project/storage/base',
     'PhabricatorProjectEditController' => 'applications/project/controller/edit',
     'PhabricatorProjectListController' => 'applications/project/controller/list',
     'PhabricatorProjectProfile' => 'applications/project/storage/profile',
     'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
     'PhabricatorRedirectController' => 'applications/base/controller/redirect',
     'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
     'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion',
     'PhabricatorRemarkupRuleImageMacro' => 'infrastructure/markup/remarkup/markuprule/imagemacro',
     'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest',
     'PhabricatorRepository' => 'applications/repository/storage/repository',
     'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/arcanistproject',
     'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/arcansistprojectedit',
     'PhabricatorRepositoryCommit' => 'applications/repository/storage/commit',
     'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/base',
     'PhabricatorRepositoryCommitData' => 'applications/repository/storage/commitdata',
     'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base',
     'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/herald',
     'PhabricatorRepositoryCommitMessageDetailParser' => 'applications/repository/parser/base',
     'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/base',
     'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/base',
     'PhabricatorRepositoryCommitTaskDaemon' => 'applications/repository/daemon/committask',
     'PhabricatorRepositoryController' => 'applications/repository/controller/base',
     'PhabricatorRepositoryCreateController' => 'applications/repository/controller/create',
     'PhabricatorRepositoryDAO' => 'applications/repository/storage/base',
     'PhabricatorRepositoryDaemon' => 'applications/repository/daemon/base',
     'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'applications/repository/parser/default',
     'PhabricatorRepositoryEditController' => 'applications/repository/controller/edit',
     'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/git',
     'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git',
     'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/git',
     'PhabricatorRepositoryGitFetchDaemon' => 'applications/repository/daemon/gitfetch',
     'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification',
     'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive',
     'PhabricatorRepositoryListController' => 'applications/repository/controller/list',
     'PhabricatorRepositoryShortcut' => 'applications/repository/storage/shortcut',
     'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/svn',
     'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/svn',
     'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/svn',
     'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype',
     'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument',
     'PhabricatorSearchBaseController' => 'applications/search/controller/base',
     'PhabricatorSearchController' => 'applications/search/controller/search',
     'PhabricatorSearchDAO' => 'applications/search/storage/base',
     'PhabricatorSearchDifferentialIndexer' => 'applications/search/index/indexer/differential',
     'PhabricatorSearchDocument' => 'applications/search/storage/document/document',
     'PhabricatorSearchDocumentField' => 'applications/search/storage/document/field',
     'PhabricatorSearchDocumentIndexer' => 'applications/search/index/indexer/base',
     'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/relationship',
     'PhabricatorSearchExecutor' => 'applications/search/execute/base',
     'PhabricatorSearchField' => 'applications/search/constants/field',
     'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest',
     'PhabricatorSearchMySQLExecutor' => 'applications/search/execute/mysql',
     'PhabricatorSearchQuery' => 'applications/search/storage/query',
     'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
     'PhabricatorStandardPageView' => 'view/page/standard',
     'PhabricatorStatusController' => 'applications/status/base',
     'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/taskmaster',
     'PhabricatorTimelineCursor' => 'infrastructure/daemon/timeline/storage/cursor',
     'PhabricatorTimelineDAO' => 'infrastructure/daemon/timeline/storage/base',
     'PhabricatorTimelineEvent' => 'infrastructure/daemon/timeline/storage/event',
     'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/eventdata',
     'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator',
     'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
     'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
     'PhabricatorUIExample' => 'applications/uiexample/examples/base',
     'PhabricatorUIExampleController' => 'applications/uiexample/controller/base',
     'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/render',
     'PhabricatorUIListFilterExample' => 'applications/uiexample/examples/listfilter',
     'PhabricatorUIPagerExample' => 'applications/uiexample/examples/pager',
     'PhabricatorUser' => 'applications/people/storage/user',
     'PhabricatorUserDAO' => 'applications/people/storage/base',
     'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
     'PhabricatorUserPreferences' => 'applications/people/storage/preferences',
     'PhabricatorUserProfile' => 'applications/people/storage/profile',
     'PhabricatorUserSettingsController' => 'applications/people/controller/settings',
     'PhabricatorWorker' => 'infrastructure/daemon/workers/worker',
     'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/base',
     'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/task',
     'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/taskdata',
     'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/workertaskdetail',
     'PhabricatorXHPASTViewController' => 'applications/xhpastview/controller/base',
     'PhabricatorXHPASTViewDAO' => 'applications/xhpastview/storage/base',
     'PhabricatorXHPASTViewFrameController' => 'applications/xhpastview/controller/viewframe',
     'PhabricatorXHPASTViewFramesetController' => 'applications/xhpastview/controller/viewframeset',
     'PhabricatorXHPASTViewInputController' => 'applications/xhpastview/controller/viewinput',
     'PhabricatorXHPASTViewPanelController' => 'applications/xhpastview/controller/viewpanel',
     'PhabricatorXHPASTViewParseTree' => 'applications/xhpastview/storage/parsetree',
     'PhabricatorXHPASTViewRunController' => 'applications/xhpastview/controller/run',
     'PhabricatorXHPASTViewStreamController' => 'applications/xhpastview/controller/viewstream',
     'PhabricatorXHPASTViewTreeController' => 'applications/xhpastview/controller/viewtree',
     'PhabricatorXHProfController' => 'applications/xhprof/controller/base',
     'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile',
     'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol',
     'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel',
   ),
   'function' =>
   array(
     '_qsprintf_check_scalar_type' => 'storage/qsprintf',
     '_qsprintf_check_type' => 'storage/qsprintf',
     'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
     'celerity_register_resource_map' => 'infrastructure/celerity/map',
     'javelin_render_tag' => 'infrastructure/javelin/markup',
     'phabricator_format_relative_time' => 'view/utils',
     'phabricator_format_timestamp' => 'view/utils',
     'phabricator_format_units_generic' => 'view/utils',
     'phabricator_render_form' => 'infrastructure/javelin/markup',
     'qsprintf' => 'storage/qsprintf',
     'queryfx' => 'storage/queryfx',
     'queryfx_all' => 'storage/queryfx',
     'queryfx_one' => 'storage/queryfx',
     'require_celerity_resource' => 'infrastructure/celerity/api',
     'vqsprintf' => 'storage/qsprintf',
     'vqueryfx' => 'storage/queryfx',
     'vqueryfx_all' => 'storage/queryfx',
     'xsprintf_query' => 'storage/qsprintf',
   ),
   'requires_class' =>
   array(
     'Aphront400Response' => 'AphrontResponse',
     'Aphront404Response' => 'AphrontResponse',
     'AphrontAjaxResponse' => 'AphrontResponse',
     'AphrontCrumbsView' => 'AphrontView',
     'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
     'AphrontDefaultApplicationController' => 'AphrontController',
     'AphrontDialogResponse' => 'AphrontResponse',
     'AphrontDialogView' => 'AphrontView',
     'AphrontErrorView' => 'AphrontView',
     'AphrontFileResponse' => 'AphrontResponse',
     'AphrontFormCheckboxControl' => 'AphrontFormControl',
     'AphrontFormControl' => 'AphrontView',
     'AphrontFormDividerControl' => 'AphrontFormControl',
     'AphrontFormFileControl' => 'AphrontFormControl',
     'AphrontFormMarkupControl' => 'AphrontFormControl',
     'AphrontFormPasswordControl' => 'AphrontFormControl',
     'AphrontFormRecaptchaControl' => 'AphrontFormControl',
     'AphrontFormSelectControl' => 'AphrontFormControl',
     'AphrontFormStaticControl' => 'AphrontFormControl',
     'AphrontFormSubmitControl' => 'AphrontFormControl',
     'AphrontFormTextAreaControl' => 'AphrontFormControl',
     'AphrontFormTextControl' => 'AphrontFormControl',
     'AphrontFormToggleButtonsControl' => 'AphrontFormControl',
     'AphrontFormTokenizerControl' => 'AphrontFormControl',
     'AphrontFormView' => 'AphrontView',
     'AphrontHeadsupActionListView' => 'AphrontView',
     'AphrontHeadsupActionView' => 'AphrontView',
     'AphrontListFilterView' => 'AphrontView',
     'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
     'AphrontNullView' => 'AphrontView',
     'AphrontPageView' => 'AphrontView',
     'AphrontPagerView' => 'AphrontView',
     'AphrontPanelView' => 'AphrontView',
     'AphrontQueryConnectionException' => 'AphrontQueryException',
     'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
     'AphrontQueryCountException' => 'AphrontQueryException',
     'AphrontQueryDuplicateKeyException' => 'AphrontQueryException',
     'AphrontQueryObjectMissingException' => 'AphrontQueryException',
     'AphrontQueryParameterException' => 'AphrontQueryException',
     'AphrontQueryRecoverableException' => 'AphrontQueryException',
     'AphrontRedirectException' => 'AphrontException',
     'AphrontRedirectResponse' => 'AphrontResponse',
     'AphrontRequestFailureView' => 'AphrontView',
     'AphrontSideNavView' => 'AphrontView',
     'AphrontTableView' => 'AphrontView',
     'AphrontTokenizerTemplateView' => 'AphrontView',
     'AphrontTypeaheadTemplateView' => 'AphrontView',
     'AphrontWebpageResponse' => 'AphrontResponse',
     'CelerityResourceController' => 'AphrontController',
     'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
     'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod',
     'ConduitAPI_daemon_launched_Method' => 'ConduitAPIMethod',
     'ConduitAPI_daemon_log_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getalldiffs_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getdiff_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getrevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getrevisionfeedback_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
+    'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'ConduitAPIMethod',
     'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
     'ConduitAPI_path_getowners_Method' => 'ConduitAPIMethod',
     'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
     'ConduitAPI_user_whoami_Method' => 'ConduitAPIMethod',
     'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
     'DarkConsoleController' => 'PhabricatorController',
     'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
     'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
     'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
     'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin',
     'DifferentialAddCommentView' => 'AphrontView',
     'DifferentialAttachController' => 'DifferentialController',
     'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
     'DifferentialChangeset' => 'DifferentialDAO',
     'DifferentialChangesetDetailView' => 'AphrontView',
     'DifferentialChangesetListView' => 'AphrontView',
     'DifferentialChangesetViewController' => 'DifferentialController',
     'DifferentialComment' => 'DifferentialDAO',
     'DifferentialCommentMail' => 'DifferentialMail',
     'DifferentialCommentPreviewController' => 'DifferentialController',
     'DifferentialCommentSaveController' => 'DifferentialController',
     'DifferentialController' => 'PhabricatorController',
     'DifferentialDAO' => 'PhabricatorLiskDAO',
     'DifferentialDiff' => 'DifferentialDAO',
     'DifferentialDiffContentMail' => 'DifferentialMail',
     'DifferentialDiffCreateController' => 'DifferentialController',
     'DifferentialDiffProperty' => 'DifferentialDAO',
     'DifferentialDiffTableOfContentsView' => 'AphrontView',
     'DifferentialDiffViewController' => 'DifferentialController',
     'DifferentialHunk' => 'DifferentialDAO',
     'DifferentialInlineComment' => 'DifferentialDAO',
     'DifferentialInlineCommentEditController' => 'DifferentialController',
     'DifferentialInlineCommentPreviewController' => 'DifferentialController',
     'DifferentialInlineCommentView' => 'AphrontView',
     'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
     'DifferentialReviewRequestMail' => 'DifferentialMail',
     'DifferentialRevision' => 'DifferentialDAO',
     'DifferentialRevisionCommentListView' => 'AphrontView',
     'DifferentialRevisionCommentView' => 'AphrontView',
     'DifferentialRevisionDetailView' => 'AphrontView',
     'DifferentialRevisionEditController' => 'DifferentialController',
     'DifferentialRevisionListController' => 'DifferentialController',
     'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
     'DifferentialRevisionViewController' => 'DifferentialController',
     'DifferentialSubscribeController' => 'DifferentialController',
     'DifferentialViewTime' => 'DifferentialDAO',
     'DiffusionBranchTableView' => 'DiffusionView',
     'DiffusionBrowseController' => 'DiffusionController',
     'DiffusionBrowseFileController' => 'DiffusionController',
     'DiffusionBrowseTableView' => 'DiffusionView',
     'DiffusionChangeController' => 'DiffusionController',
     'DiffusionCommitChangeTableView' => 'DiffusionView',
     'DiffusionCommitController' => 'DiffusionController',
     'DiffusionController' => 'PhabricatorController',
     'DiffusionDiffController' => 'DiffusionController',
     'DiffusionGitBranchQuery' => 'DiffusionBranchQuery',
     'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionGitDiffQuery' => 'DiffusionDiffQuery',
     'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
     'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionGitLastModifiedQuery' => 'DiffusionLastModifiedQuery',
     'DiffusionGitRequest' => 'DiffusionRequest',
     'DiffusionHistoryController' => 'DiffusionController',
     'DiffusionHistoryTableView' => 'DiffusionView',
     'DiffusionHomeController' => 'DiffusionController',
     'DiffusionLastModifiedController' => 'DiffusionController',
     'DiffusionPathCompleteController' => 'DiffusionController',
     'DiffusionPathValidateController' => 'DiffusionController',
     'DiffusionRepositoryController' => 'DiffusionController',
     'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionSvnDiffQuery' => 'DiffusionDiffQuery',
     'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery',
     'DiffusionSvnHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionSvnLastModifiedQuery' => 'DiffusionLastModifiedQuery',
     'DiffusionSvnRequest' => 'DiffusionRequest',
     'DiffusionView' => 'AphrontView',
     'HeraldAction' => 'HeraldDAO',
     'HeraldApplyTranscript' => 'HeraldDAO',
     'HeraldCommitAdapter' => 'HeraldObjectAdapter',
     'HeraldCondition' => 'HeraldDAO',
     'HeraldController' => 'PhabricatorController',
     'HeraldDAO' => 'PhabricatorLiskDAO',
     'HeraldDeleteController' => 'HeraldController',
     'HeraldDifferentialRevisionAdapter' => 'HeraldObjectAdapter',
     'HeraldDryRunAdapter' => 'HeraldObjectAdapter',
     'HeraldHomeController' => 'HeraldController',
     'HeraldNewController' => 'HeraldController',
     'HeraldRule' => 'HeraldDAO',
     'HeraldRuleController' => 'HeraldController',
     'HeraldTestConsoleController' => 'HeraldController',
     'HeraldTranscript' => 'HeraldDAO',
     'HeraldTranscriptController' => 'HeraldController',
     'HeraldTranscriptListController' => 'HeraldController',
     'ManiphestController' => 'PhabricatorController',
     'ManiphestDAO' => 'PhabricatorLiskDAO',
     'ManiphestTask' => 'ManiphestDAO',
     'ManiphestTaskDetailController' => 'ManiphestController',
     'ManiphestTaskEditController' => 'ManiphestController',
     'ManiphestTaskListController' => 'ManiphestController',
     'ManiphestTaskListView' => 'AphrontView',
     'ManiphestTaskSelectorSearchController' => 'ManiphestController',
     'ManiphestTaskSummaryView' => 'AphrontView',
     'ManiphestTransaction' => 'ManiphestDAO',
     'ManiphestTransactionDetailView' => 'AphrontView',
     'ManiphestTransactionListView' => 'AphrontView',
     'ManiphestTransactionSaveController' => 'ManiphestController',
     'Phabricator404Controller' => 'PhabricatorController',
     'PhabricatorAuthController' => 'PhabricatorController',
     'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
     'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
     'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
     'PhabricatorConduitController' => 'PhabricatorController',
     'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
     'PhabricatorConduitLogController' => 'PhabricatorConduitController',
     'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
     'PhabricatorController' => 'AphrontController',
     'PhabricatorDaemon' => 'PhutilDaemon',
     'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonController' => 'PhabricatorController',
     'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO',
     'PhabricatorDaemonLog' => 'PhabricatorDaemonDAO',
     'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO',
     'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonTimelineConsoleController' => 'PhabricatorDaemonController',
     'PhabricatorDaemonTimelineEventController' => 'PhabricatorDaemonController',
     'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryController' => 'PhabricatorController',
     'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
     'PhabricatorDraft' => 'PhabricatorDraftDAO',
     'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
     'PhabricatorEditPreferencesController' => 'PhabricatorPreferencesController',
     'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
     'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
     'PhabricatorFile' => 'PhabricatorFileDAO',
     'PhabricatorFileController' => 'PhabricatorController',
     'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFileImageMacro' => 'PhabricatorFileDAO',
     'PhabricatorFileListController' => 'PhabricatorFileController',
     'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
     'PhabricatorFileUploadController' => 'PhabricatorFileController',
     'PhabricatorFileViewController' => 'PhabricatorFileController',
     'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker',
     'PhabricatorLiskDAO' => 'LiskDAO',
     'PhabricatorLoginController' => 'PhabricatorAuthController',
     'PhabricatorLogoutController' => 'PhabricatorAuthController',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMetaMTAController' => 'PhabricatorController',
     'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
     'PhabricatorMetaMTADaemon' => 'PhabricatorDaemon',
     'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController',
     'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController',
     'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController',
     'PhabricatorOAuthFailureView' => 'AphrontView',
     'PhabricatorOAuthLoginController' => 'PhabricatorAuthController',
     'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthProviderGithub' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController',
     'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
     'PhabricatorOwnersController' => 'PhabricatorController',
     'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
     'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
     'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
     'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO',
     'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO',
     'PhabricatorPHID' => 'PhabricatorPHIDDAO',
     'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDController' => 'PhabricatorController',
     'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
     'PhabricatorPHIDListController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
     'PhabricatorPeopleController' => 'PhabricatorController',
     'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController',
     'PhabricatorPreferencesController' => 'PhabricatorController',
     'PhabricatorProject' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectController' => 'PhabricatorController',
     'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
     'PhabricatorProjectEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectListController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
     'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
     'PhabricatorRedirectController' => 'PhabricatorController',
     'PhabricatorRemarkupRuleDifferential' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleManiphest' => 'PhutilRemarkupRule',
     'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker',
     'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker',
     'PhabricatorRepositoryCommitTaskDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryController' => 'PhabricatorController',
     'PhabricatorRepositoryCreateController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon',
     'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'PhabricatorRepositoryCommitMessageDetailParser',
     'PhabricatorRepositoryEditController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
     'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
     'PhabricatorRepositoryGitFetchDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',
     'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker',
     'PhabricatorSearchBaseController' => 'PhabricatorController',
     'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
     'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO',
     'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor',
     'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
     'PhabricatorStandardPageView' => 'AphrontPageView',
     'PhabricatorStatusController' => 'PhabricatorController',
     'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon',
     'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
     'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
     'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
     'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
     'PhabricatorUIExampleController' => 'PhabricatorController',
     'PhabricatorUIExampleRenderController' => 'PhabricatorUIExampleController',
     'PhabricatorUIListFilterExample' => 'PhabricatorUIExample',
     'PhabricatorUIPagerExample' => 'PhabricatorUIExample',
     'PhabricatorUser' => 'PhabricatorUserDAO',
     'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
     'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
     'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
     'PhabricatorUserProfile' => 'PhabricatorUserDAO',
     'PhabricatorUserSettingsController' => 'PhabricatorPeopleController',
     'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO',
     'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO',
     'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO',
     'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController',
     'PhabricatorXHPASTViewController' => 'PhabricatorController',
     'PhabricatorXHPASTViewDAO' => 'PhabricatorLiskDAO',
     'PhabricatorXHPASTViewFrameController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewFramesetController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewInputController' => 'PhabricatorXHPASTViewPanelController',
     'PhabricatorXHPASTViewPanelController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewParseTree' => 'PhabricatorXHPASTViewDAO',
     'PhabricatorXHPASTViewRunController' => 'PhabricatorXHPASTViewController',
     'PhabricatorXHPASTViewStreamController' => 'PhabricatorXHPASTViewPanelController',
     'PhabricatorXHPASTViewTreeController' => 'PhabricatorXHPASTViewPanelController',
     'PhabricatorXHProfController' => 'PhabricatorController',
     'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController',
     'PhabricatorXHProfProfileSymbolView' => 'AphrontView',
     'PhabricatorXHProfProfileTopLevelView' => 'AphrontView',
   ),
   'requires_interface' =>
   array(
   ),
 ));
diff --git a/src/applications/conduit/controller/console/PhabricatorConduitConsoleController.php b/src/applications/conduit/controller/console/PhabricatorConduitConsoleController.php
index 4bee4284c..4ffb6087f 100644
--- a/src/applications/conduit/controller/console/PhabricatorConduitConsoleController.php
+++ b/src/applications/conduit/controller/console/PhabricatorConduitConsoleController.php
@@ -1,184 +1,184 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 class PhabricatorConduitConsoleController
   extends PhabricatorConduitController {
 
   private $method;
 
   public function willProcessRequest(array $data) {
     $this->method = idx($data, 'method');
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
 
     $methods = $this->getAllMethods();
     if (empty($methods[$this->method])) {
       $this->method = key($methods);
     }
 
     $method_class = $methods[$this->method];
     PhutilSymbolLoader::loadClass($method_class);
     $method_object = newv($method_class, array());
 
 
     $error_description = array();
     $error_types = $method_object->defineErrorTypes();
     if ($error_types) {
       $error_description[] = '<ul>';
       foreach ($error_types as $error => $meaning) {
         $error_description[] =
           '<li>'.
             '<strong>'.phutil_escape_html($error).':</strong> '.
             phutil_escape_html($meaning).
           '</li>';
       }
       $error_description[] = '</ul>';
       $error_description = implode("\n", $error_description);
     } else {
       $error_description = "This method does not raise any specific errors.";
     }
 
     $form = new AphrontFormView();
     $form
       ->setUser($request->getUser())
       ->setAction('/api/'.$this->method)
       ->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('Description')
           ->setValue($method_object->getMethodDescription()))
       ->appendChild(
         id(new AphrontFormStaticControl())
           ->setLabel('Returns')
           ->setValue($method_object->defineReturnType()))
       ->appendChild(
         id(new AphrontFormMarkupControl())
           ->setLabel('Errors')
           ->setValue($error_description))
       ->appendChild(
         '<p class="aphront-form-instructions">Enter parameters using '.
         '<strong>JSON</strong>. For instance, to enter a list, type: '.
         '<tt>["apple", "banana", "cherry"]</tt>');
 
     $params = $method_object->defineParamTypes();
     foreach ($params as $param => $desc) {
       $form->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel($param)
           ->setName("params[{$param}]")
-          ->setCaption($desc));
+          ->setCaption(phutil_escape_html($desc)));
     }
 
     $form
       ->appendChild(
         id(new AphrontFormSelectControl())
           ->setLabel('Output Format')
           ->setName('output')
           ->setOptions(
             array(
               'human' => 'Human Readable',
               'json'  => 'JSON',
             )))
       ->appendChild(
         id(new AphrontFormSubmitControl())
           ->setValue('Call Method'));
 
     $panel = new AphrontPanelView();
     $panel->setHeader('Conduit API: '.phutil_escape_html($this->method));
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
 
     $view = new AphrontSideNavView();
     foreach ($this->buildNavItems() as $item) {
       $view->addNavItem($item);
     }
 
     $view->appendChild($panel);
 
     return $this->buildStandardPageResponse(
       array($view),
       array(
         'title' => 'Conduit Console',
         'tab'   => 'console',
       ));
   }
 
   private function buildNavItems() {
     $classes = $this->getAllMethodImplementationClasses();
     $method_names = array();
     foreach ($classes as $method_class) {
       $method_name = ConduitAPIMethod::getAPIMethodNameFromClassName(
         $method_class);
       $parts = explode('.', $method_name);
       $method_names[] = array(
         'full_name'   => $method_name,
         'group_name'  => reset($parts),
       );
     }
     $method_names = igroup($method_names, 'group_name');
     ksort($method_names);
 
     $items = array();
     foreach ($method_names as $group => $methods) {
       $items[] = phutil_render_tag(
         'a',
         array(
         ),
         phutil_escape_html($group));
       foreach ($methods as $method) {
         $method_name = $method['full_name'];
         $selected = ($method_name == $this->method);
         $items[] = phutil_render_tag(
           'a',
           array(
             'class' => $selected ? 'aphront-side-nav-selected' : null,
             'href'  => '/conduit/method/'.$method_name,
           ),
           '<span style="padding-left: 1em;">'.
             phutil_escape_html($method_name).
           '</span>');
       }
       $items[] = '<hr />';
     }
     // Pop off the last '<hr />'.
     array_pop($items);
 
     return $items;
   }
 
   private function getAllMethods() {
     $classes = $this->getAllMethodImplementationClasses();
     $methods = array();
     foreach ($classes as $class) {
       $name = ConduitAPIMethod::getAPIMethodNameFromClassName($class);
       $methods[$name] = $class;
     }
     return $methods;
   }
 
   private function getAllMethodImplementationClasses() {
     $classes = id(new PhutilSymbolLoader())
       ->setAncestorClass('ConduitAPIMethod')
       ->setType('class')
       ->selectSymbolsWithoutLoading();
     return array_values(ipull($classes, 'name'));
   }
 
 }
diff --git a/src/applications/conduit/method/differential/find/ConduitAPI_differential_find_Method.php b/src/applications/conduit/method/differential/find/ConduitAPI_differential_find_Method.php
index fc4b986f1..1c0067471 100644
--- a/src/applications/conduit/method/differential/find/ConduitAPI_differential_find_Method.php
+++ b/src/applications/conduit/method/differential/find/ConduitAPI_differential_find_Method.php
@@ -1,77 +1,82 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 class ConduitAPI_differential_find_Method extends ConduitAPIMethod {
 
   public function getMethodDescription() {
     return "Query Differential revisions which match certain criteria.";
   }
 
   public function defineParamTypes() {
     $types = array(
       DifferentialRevisionListData::QUERY_OPEN_OWNED,
       DifferentialRevisionListData::QUERY_COMMITTABLE,
       DifferentialRevisionListData::QUERY_REVISION_IDS,
       DifferentialRevisionListData::QUERY_PHIDS,
     );
 
     $types = implode(', ', $types);
 
     return array(
       'query' => 'required enum<'.$types.'>',
-      'guids' => 'required nonempty list<phid>',
+      'guids' => 'required nonempty list<guids>',
     );
   }
 
   public function defineReturnType() {
     return 'nonempty list<dict>';
   }
 
   public function defineErrorTypes() {
     return array(
     );
   }
 
   protected function execute(ConduitAPIRequest $request) {
     $query = $request->getValue('query');
-    $phids = $request->getValue('guids');
+    $guids = $request->getValue('guids');
+
+    $results = array();
+    if (!$guids) {
+      return $results;
+    }
 
     $revisions = id(new DifferentialRevisionListData(
       $query,
-      (array)$phids))
+      (array)$guids))
       ->loadRevisions();
 
-    $results = array();
     foreach ($revisions as $revision) {
       $diff = $revision->loadActiveDiff();
       if (!$diff) {
         continue;
       }
       $results[] = array(
         'id'          => $revision->getID(),
+        'phid'        => $revision->getPHID(),
         'name'        => $revision->getTitle(),
         'statusName'  => DifferentialRevisionStatus::getNameForRevisionStatus(
           $revision->getStatus()),
         'sourcePath'  => $diff->getSourcePath(),
       );
     }
 
     return $results;
   }
 
 }
diff --git a/src/applications/conduit/method/differential/updatetaskrevisionassoc/ConduitAPI_differential_updatetaskrevisionassoc_Method.php b/src/applications/conduit/method/differential/updatetaskrevisionassoc/ConduitAPI_differential_updatetaskrevisionassoc_Method.php
new file mode 100644
index 000000000..45a3a6829
--- /dev/null
+++ b/src/applications/conduit/method/differential/updatetaskrevisionassoc/ConduitAPI_differential_updatetaskrevisionassoc_Method.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ConduitAPI_differential_updatetaskrevisionassoc_Method
+  extends ConduitAPIMethod {
+  public function getMethodDescription() {
+    return "Given a task together with its original and new associated ".
+      "revisions, update the revisions for their attached_tasks.";
+  }
+
+  public function defineParamTypes() {
+    return array(
+      'task_phid' => 'required nonempty string',
+      'orig_rev_phids' => 'required list<string>',
+      'new_rev_phids' => 'required list<string>',
+    );
+  }
+
+  public function defineReturnType() {
+    return 'void';
+  }
+
+  public function defineErrorTypes() {
+    return array(
+      'ERR_NO_TASKATTACHER_DEFINED' => 'No task attacher defined.',
+    );
+  }
+
+  protected function execute(ConduitAPIRequest $request) {
+    $task_phid = $request->getValue('task_phid');
+    $orig_rev_phids = $request->getValue('orig_rev_phids');
+    if (empty($orig_rev_phids)) {
+      $orig_rev_phids = array();
+    }
+
+    $new_rev_phids = $request->getValue('new_rev_phids');
+    if (empty($new_rev_phids)) {
+      $new_rev_phids = array();
+    }
+
+    $task_class = PhabricatorEnv::getEnvConfig(
+      'differential.attach-task-class');
+    if (!$task_class) {
+      throw new ConduitException('ERR_NO_TASKATTACHER_DEFINED');
+    }
+
+    PhutilSymbolLoader::loadClass($task_class);
+    $task_attacher = newv($task_class, array());
+    $task_attacher->updateTaskRevisionAssoc(
+      $task_phid,
+      $orig_rev_phids,
+      $new_rev_phids);
+  }
+
+}
+
diff --git a/src/applications/conduit/method/differential/updatetaskrevisionassoc/__init__.php b/src/applications/conduit/method/differential/updatetaskrevisionassoc/__init__.php
new file mode 100644
index 000000000..0ad02cea4
--- /dev/null
+++ b/src/applications/conduit/method/differential/updatetaskrevisionassoc/__init__.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/conduit/method/base');
+phutil_require_module('phabricator', 'applications/conduit/protocol/exception');
+phutil_require_module('phabricator', 'infrastructure/env');
+
+phutil_require_module('phutil', 'symbols');
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('ConduitAPI_differential_updatetaskrevisionassoc_Method.php');
diff --git a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php
index 835250f9f..316a9b340 100644
--- a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php
+++ b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php
@@ -1,876 +1,613 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 class DifferentialRevisionViewController extends DifferentialController {
 
   private $revisionID;
 
   public function willProcessRequest(array $data) {
     $this->revisionID = $data['id'];
   }
 
   public function processRequest() {
 
     $request = $this->getRequest();
     $user = $request->getUser();
 
     $revision = id(new DifferentialRevision())->load($this->revisionID);
     if (!$revision) {
       return new Aphront404Response();
     }
 
     $revision->loadRelationships();
 
     $diffs = $revision->loadDiffs();
 
     if (!$diffs) {
       throw new Exception(
         "This revision has no diffs. Something has gone quite wrong.");
     }
 
     $diff_vs = $request->getInt('vs');
 
     $target = end($diffs);
     $target_id = $request->getInt('id');
     if ($target_id) {
       if (isset($diffs[$target_id])) {
         $target = $diffs[$target_id];
       }
     }
 
     $diffs = mpull($diffs, null, 'getID');
     if (empty($diffs[$diff_vs])) {
       $diff_vs = null;
     }
 
     list($changesets, $vs_map) =
       $this->loadChangesetsAndVsMap($diffs, $diff_vs, $target);
 
     $comments = $revision->loadComments();
     $comments = array_merge(
       $this->getImplicitComments($revision),
       $comments);
 
     $all_changesets = $changesets;
     $inlines = $this->loadInlineComments($comments, $all_changesets);
 
     $object_phids = array_merge(
       $revision->getReviewers(),
       $revision->getCCPHIDs(),
       $revision->loadCommitPHIDs(),
       array(
         $revision->getAuthorPHID(),
         $user->getPHID(),
       ),
       mpull($comments, 'getAuthorPHID'));
     foreach ($revision->getAttached() as $type => $phids) {
       foreach ($phids as $phid => $info) {
         $object_phids[] = $phid;
       }
     }
     $object_phids = array_unique($object_phids);
 
     $handles = id(new PhabricatorObjectHandleData($object_phids))
       ->loadHandles();
 
     $request_uri = $request->getRequestURI();
 
     $limit = 100;
     $large = $request->getStr('large');
     if (count($changesets) > $limit && !$large) {
       $count = number_format(count($changesets));
       $warning = new AphrontErrorView();
       $warning->setTitle('Very Large Diff');
       $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING);
       $warning->setWidth(AphrontErrorView::WIDTH_WIDE);
       $warning->appendChild(
         "<p>This diff is very large and affects {$count} files. Use ".
         "Table of Contents to open files in a standalone view. ".
         "<strong>".
           phutil_render_tag(
             'a',
             array(
               'href' => $request_uri->alter('large', 'true'),
             ),
             'Show All Files Inline').
         "</strong>");
       $warning = $warning->render();
 
       $visible_changesets = array();
     } else {
       $warning = null;
       $visible_changesets = $changesets;
     }
 
     $diff_properties = id(new DifferentialDiffProperty())->loadAllWhere(
       'diffID = %d AND name IN (%Ls)',
       $target->getID(),
       array(
         'arc:lint',
         'arc:unit',
       ));
     $diff_properties = mpull($diff_properties, 'getData', 'getName');
 
     $revision_detail = new DifferentialRevisionDetailView();
     $revision_detail->setRevision($revision);
 
     $custom_renderer_class = PhabricatorEnv::getEnvConfig(
       'differential.revision-custom-detail-renderer');
     if ($custom_renderer_class) {
       PhutilSymbolLoader::loadClass($custom_renderer_class);
       $custom_renderer =
         newv($custom_renderer_class, array());
     }
 
     $properties = $this->getRevisionProperties(
       $revision,
       $target,
       $handles,
       $diff_properties);
     if ($custom_renderer) {
       $properties = array_merge(
         $properties,
         $custom_renderer->generateProperties($revision, $target));
     }
 
     $revision_detail->setProperties($properties);
 
     $actions = $this->getRevisionActions($revision);
     if ($custom_renderer) {
       $actions = array_merge(
         $actions,
         $custom_renderer->generateActionLinks($revision, $target));
     }
 
+    $whitespace = $request->getStr(
+      'whitespace',
+      DifferentialChangesetParser::WHITESPACE_IGNORE_TRAILING
+    );
+
     $revision_detail->setActions($actions);
 
     $revision_detail->setUser($user);
 
     $comment_view = new DifferentialRevisionCommentListView();
     $comment_view->setComments($comments);
     $comment_view->setHandles($handles);
     $comment_view->setInlineComments($inlines);
     $comment_view->setChangesets($all_changesets);
     $comment_view->setUser($user);
     $comment_view->setTargetDiff($target);
 
+    $changeset_view = new DifferentialChangesetListView();
+    $changeset_view->setChangesets($visible_changesets);
+    $changeset_view->setEditable(true);
+    $changeset_view->setRevision($revision);
+    $changeset_view->setVsMap($vs_map);
+    $changeset_view->setWhitespace($whitespace);
+
     $diff_history = new DifferentialRevisionUpdateHistoryView();
     $diff_history->setDiffs($diffs);
     $diff_history->setSelectedVersusDiffID($diff_vs);
     $diff_history->setSelectedDiffID($target->getID());
-    $diff_history->setSelectedWhitespace($request->getStr('whitespace'));
+    $diff_history->setSelectedWhitespace($whitespace);
 
     $toc_view = new DifferentialDiffTableOfContentsView();
     $toc_view->setChangesets($changesets);
     $toc_view->setStandaloneViewLink(empty($visible_changesets));
     $toc_view->setVsMap($vs_map);
     $toc_view->setRevisionID($revision->getID());
+    $toc_view->setWhitespace($whitespace);
 
-    $changeset_view = new DifferentialChangesetListView();
-    $changeset_view->setChangesets($visible_changesets);
-    $changeset_view->setEditable(true);
-    $changeset_view->setRevision($revision);
-    $changeset_view->setVsMap($vs_map);
-    $changeset_view->setWhitespace($request->getStr('whitespace'));
 
     $draft = id(new PhabricatorDraft())->loadOneWhere(
       'authorPHID = %s AND draftKey = %s',
       $user->getPHID(),
       'differential-comment-'.$revision->getID());
     if ($draft) {
       $draft = $draft->getDraft();
     } else {
       $draft = null;
     }
 
     $comment_form = new DifferentialAddCommentView();
     $comment_form->setRevision($revision);
     $comment_form->setActions($this->getRevisionCommentActions($revision));
     $comment_form->setActionURI('/differential/comment/save/');
     $comment_form->setUser($user);
     $comment_form->setDraft($draft);
 
     $this->updateViewTime($user->getPHID(), $revision->getPHID());
 
     return $this->buildStandardPageResponse(
       '<div class="differential-primary-pane">'.
         $revision_detail->render().
         $comment_view->render().
         $diff_history->render().
         $warning.
         $toc_view->render().
         $changeset_view->render().
         $comment_form->render().
       '</div>',
       array(
         'title' => $revision->getTitle(),
       ));
   }
 
   private function getImplicitComments(DifferentialRevision $revision) {
 
     $template = new DifferentialComment();
     $template->setAuthorPHID($revision->getAuthorPHID());
     $template->setRevisionID($revision->getID());
     $template->setDateCreated($revision->getDateCreated());
 
     $comments = array();
 
     if (strlen($revision->getSummary())) {
       $summary_comment = clone $template;
       $summary_comment->setContent($revision->getSummary());
       $summary_comment->setAction(DifferentialAction::ACTION_SUMMARIZE);
       $comments[] = $summary_comment;
     }
 
     if (strlen($revision->getTestPlan())) {
       $testplan_comment = clone $template;
       $testplan_comment->setContent($revision->getTestPlan());
       $testplan_comment->setAction(DifferentialAction::ACTION_TESTPLAN);
       $comments[] = $testplan_comment;
     }
 
     return $comments;
   }
 
   private function getRevisionProperties(
     DifferentialRevision $revision,
     DifferentialDiff $diff,
     array $handles,
     array $diff_properties) {
 
     $properties = array();
 
     $status = $revision->getStatus();
     $status = DifferentialRevisionStatus::getNameForRevisionStatus($status);
     $properties['Revision Status'] = '<strong>'.$status.'</strong>';
 
     $author = $handles[$revision->getAuthorPHID()];
     $properties['Author'] = $author->renderLink();
 
     $properties['Reviewers'] = $this->renderHandleLinkList(
       array_select_keys(
         $handles,
         $revision->getReviewers()));
 
     $properties['CCs'] = $this->renderHandleLinkList(
       array_select_keys(
         $handles,
         $revision->getCCPHIDs()));
 
     $host = $diff->getSourceMachine();
     if ($host) {
       $properties['Host'] = phutil_escape_html($host);
     }
 
     $path = $diff->getSourcePath();
     if ($path) {
       $branch = $diff->getBranch() ? ' ('.$diff->getBranch().')' : '';
       $properties['Path'] = phutil_escape_html("{$path} {$branch}");
     }
 
     $lstar = DifferentialRevisionUpdateHistoryView::renderDiffLintStar($diff);
     $lmsg = DifferentialRevisionUpdateHistoryView::getDiffLintMessage($diff);
     $ldata = idx($diff_properties, 'arc:lint');
     $ltail = null;
     if ($ldata) {
       $ldata = igroup($ldata, 'path');
       $lint_messages = array();
       foreach ($ldata as $path => $messages) {
         $message_markup = array();
         foreach ($messages as $message) {
           $path = idx($message, 'path');
           $line = idx($message, 'line');
 
           $code = idx($message, 'code');
           $severity = idx($message, 'severity');
 
           $name = idx($message, 'name');
           $description = idx($message, 'description');
 
           $message_markup[] =
             '<li>'.
               '<span class="lint-severity-'.phutil_escape_html($severity).'">'.
                 phutil_escape_html(ucwords($severity)).
               '</span>'.
               ' '.
               '('.phutil_escape_html($code).') '.
               phutil_escape_html($name).
               ' at line '.phutil_escape_html($line).
               '<p>'.phutil_escape_html($description).'</p>'.
             '</li>';
         }
         $lint_messages[] =
           '<li class="lint-file-block">'.
             'Lint for <strong>'.phutil_escape_html($path).'</strong>'.
             '<ul>'.implode("\n", $message_markup).'</ul>'.
           '</li>';
       }
       $ltail =
         '<div class="differential-lint-block">'.
           '<ul>'.
             implode("\n", $lint_messages).
           '</ul>'.
         '</div>';
     }
 
     $properties['Lint'] = $lstar.' '.$lmsg.$ltail;
 
     $ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff);
     $umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff);
 
     $udata = idx($diff_properties, 'arc:unit');
     $utail = null;
     if ($udata) {
       $unit_messages = array();
       foreach ($udata as $test) {
         $name = phutil_escape_html(idx($test, 'name'));
         $result = phutil_escape_html(idx($test, 'result'));
         $userdata = phutil_escape_html(idx($test, 'userdata'));
         if (strlen($userdata) > 256) {
           $userdata = substr($userdata, 0, 256).'...';
         }
         $userdata = str_replace("\n", '<br />', $userdata);
         $unit_messages[] =
           '<tr>'.
             '<th>'.$name.'</th>'.
             '<th class="unit-test-result">'.
               '<div class="result-'.$result.'">'.
                 strtoupper($result).
               '</div>'.
             '</th>'.
             '<td>'.$userdata.'</td>'.
           '</tr>';
       }
 
       $utail =
         '<div class="differential-unit-block">'.
           '<table class="differential-unit-table">'.
             implode("\n", $unit_messages).
           '</table>'.
         '</div>';
     }
 
     $properties['Unit'] = $ustar.' '.$umsg.$utail;
 
     if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
       $tasks = $revision->getAttachedPHIDs(
         PhabricatorPHIDConstants::PHID_TYPE_TASK);
       if ($tasks) {
         $links = array();
         foreach ($tasks as $task_phid) {
           $links[] = $handles[$task_phid]->renderLink();
         }
         $properties['Maniphest Tasks'] = implode('<br />', $links);
       }
     }
 
     $commit_phids = $revision->getCommitPHIDs();
     if ($commit_phids) {
       $links = array();
       foreach ($commit_phids as $commit_phid) {
         $links[] = $handles[$commit_phid]->renderLink();
       }
       $properties['Commits'] = implode('<br />', $links);
     }
 
     return $properties;
   }
 
   private function getRevisionActions(DifferentialRevision $revision) {
     $viewer_phid = $this->getRequest()->getUser()->getPHID();
     $viewer_is_owner = ($revision->getAuthorPHID() == $viewer_phid);
     $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
     $viewer_is_cc = in_array($viewer_phid, $revision->getCCPHIDs());
     $status = $revision->getStatus();
     $revision_id = $revision->getID();
     $revision_phid = $revision->getPHID();
 
     $links = array();
 
     if ($viewer_is_owner) {
       $links[] = array(
         'class' => 'revision-edit',
         'href'  => "/differential/revision/edit/{$revision_id}/",
         'name'  => 'Edit Revision',
       );
     }
 
     if (!$viewer_is_owner && !$viewer_is_reviewer) {
       $action = $viewer_is_cc ? 'rem' : 'add';
       $links[] = array(
         'class'   => $viewer_is_cc ? 'subscribe-rem' : 'subscribe-add',
         'href'    => "/differential/subscribe/{$action}/{$revision_id}/",
         'name'    => $viewer_is_cc ? 'Unsubscribe' : 'Subscribe',
         'instant' => true,
       );
     } else {
       $links[] = array(
         'class' => 'subscribe-rem unavailable',
         'name'  => 'Automatically Subscribed',
       );
     }
 
     require_celerity_resource('phabricator-object-selector-css');
     require_celerity_resource('javelin-behavior-phabricator-object-selector');
 
     if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
       $links[] = array(
         'class' => 'attach-maniphest',
         'name'  => 'Edit Maniphest Tasks',
         'href'  => "/differential/attach/{$revision_id}/TASK/",
         'sigil' => 'workflow',
       );
     }
 
     $links[] = array(
       'class' => 'transcripts-metamta',
       'name'  => 'MetaMTA Transcripts',
       'href'  => "/mail/?phid={$revision_phid}",
     );
 
     $links[] = array(
       'class' => 'transcripts-herald',
       'name'  => 'Herald Transcripts',
       'href'  => "/herald/transcript/?phid={$revision_phid}",
     );
 
     return $links;
   }
 
 
   private function renderHandleLinkList(array $list) {
     if (empty($list)) {
       return '<em>None</em>';
     }
     return implode(', ', mpull($list, 'renderLink'));
   }
 
   private function getRevisionCommentActions(DifferentialRevision $revision) {
 
     $actions = array(
       DifferentialAction::ACTION_COMMENT => true,
     );
 
     $viewer_phid = $this->getRequest()->getUser()->getPHID();
     $viewer_is_owner = ($viewer_phid == $revision->getAuthorPHID());
     $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
 
     if ($viewer_is_owner) {
       switch ($revision->getStatus()) {
         case DifferentialRevisionStatus::NEEDS_REVIEW:
           $actions[DifferentialAction::ACTION_ABANDON] = true;
           $actions[DifferentialAction::ACTION_RETHINK] = true;
           break;
         case DifferentialRevisionStatus::NEEDS_REVISION:
           $actions[DifferentialAction::ACTION_ABANDON] = true;
           $actions[DifferentialAction::ACTION_REQUEST] = true;
           break;
         case DifferentialRevisionStatus::ACCEPTED:
           $actions[DifferentialAction::ACTION_ABANDON] = true;
           $actions[DifferentialAction::ACTION_REQUEST] = true;
           $actions[DifferentialAction::ACTION_RETHINK] = true;
           break;
         case DifferentialRevisionStatus::COMMITTED:
           break;
         case DifferentialRevisionStatus::ABANDONED:
           $actions[DifferentialAction::ACTION_RECLAIM] = true;
           break;
       }
     } else {
       switch ($revision->getStatus()) {
         case DifferentialRevisionStatus::NEEDS_REVIEW:
           $actions[DifferentialAction::ACTION_ACCEPT] = true;
           $actions[DifferentialAction::ACTION_REJECT] = true;
           $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
           break;
         case DifferentialRevisionStatus::NEEDS_REVISION:
           $actions[DifferentialAction::ACTION_ACCEPT] = true;
           $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
           break;
         case DifferentialRevisionStatus::ACCEPTED:
           $actions[DifferentialAction::ACTION_REJECT] = true;
           break;
         case DifferentialRevisionStatus::COMMITTED:
         case DifferentialRevisionStatus::ABANDONED:
           break;
       }
     }
 
     $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true;
 
     return array_keys(array_filter($actions));
   }
 
   private function loadInlineComments(array $comments, array &$changesets) {
 
     $inline_comments = array();
 
     $comment_ids = array_filter(mpull($comments, 'getID'));
     if (!$comment_ids) {
       return $inline_comments;
     }
 
     $inline_comments = id(new DifferentialInlineComment())
       ->loadAllWhere(
         'commentID in (%Ld)',
         $comment_ids);
 
     $load_changesets = array();
     foreach ($inline_comments as $inline) {
       $changeset_id = $inline->getChangesetID();
       if (isset($changesets[$changeset_id])) {
         continue;
       }
       $load_changesets[$changeset_id] = true;
     }
 
     $more_changesets = array();
     if ($load_changesets) {
       $changeset_ids = array_keys($load_changesets);
       $more_changesets += id(new DifferentialChangeset())
         ->loadAllWhere(
           'id IN (%Ld)',
           $changeset_ids);
     }
 
     if ($more_changesets) {
       $changesets += $more_changesets;
       $changesets = msort($changesets, 'getSortKey');
     }
 
     return $inline_comments;
   }
 
   private function loadChangesetsAndVsMap(array $diffs, $diff_vs, $target) {
     $load_ids = array();
     if ($diff_vs) {
       $load_ids[] = $diff_vs;
     }
     $load_ids[] = $target->getID();
 
     $raw_changesets = id(new DifferentialChangeset())
       ->loadAllWhere(
         'diffID IN (%Ld)',
         $load_ids);
     $changeset_groups = mgroup($raw_changesets, 'getDiffID');
 
     $changesets = idx($changeset_groups, $target->getID(), array());
     $changesets = mpull($changesets, null, 'getID');
 
     $vs_map = array();
     if ($diff_vs) {
       $vs_changesets = idx($changeset_groups, $diff_vs, array());
       $vs_changesets = mpull($vs_changesets, null, 'getFilename');
       foreach ($changesets as $key => $changeset) {
         $file = $changeset->getFilename();
         if (isset($vs_changesets[$file])) {
           $vs_map[$changeset->getID()] = $vs_changesets[$file]->getID();
           unset($vs_changesets[$file]);
         }
       }
       foreach ($vs_changesets as $changeset) {
         $changesets[$changeset->getID()] = $changeset;
         $vs_map[$changeset->getID()] = -1;
       }
     }
 
     $changesets = msort($changesets, 'getSortKey');
 
     return array($changesets, $vs_map);
   }
 
   private function updateViewTime($user_phid, $revision_phid) {
     $view_time =
       id(new DifferentialViewTime())
         ->setViewerPHID($user_phid)
         ->setObjectPHID($revision_phid)
         ->setViewTime(time())
         ->replace();
   }
 }
-/*
-
-
-  protected function getSandcastleURI(Diff $diff) {
-    $uri = $this->getDiffProperty($diff, 'facebook:sandcastle_uri');
-    if (!$uri) {
-      $uri = $diff->getSandboxURL();
-    }
-    return $uri;
-  }
-
-  protected function getDiffProperty(Diff $diff, $property, $default = null) {
-    $diff_id = $diff->getID();
-    if (empty($this->diffProperties[$diff_id])) {
-      $props = id(new DifferentialDiffProperty())
-        ->loadAllWhere('diffID = %s', $diff_id);
-      $dict = array_pull($props, 'getData', 'getName');
-      $this->diffProperties[$diff_id] = $dict;
-    }
-    return idx($this->diffProperties[$diff_id], $property, $default);
-  }
-
-    $diff_table->appendChild(
-      <tr>
-        <td colspan="8" class="diff-differ-submit">
-          <label>Whitespace Changes:</label>
-          {id(<select name="whitespace" />)->setOptions(
-            array(
-              'ignore-all'      => 'Ignore All',
-              'ignore-trailing' => 'Ignore Trailing',
-              'show-all'        => 'Show All',
-            ), $request->getStr('whitespace'))}{' '}
-          <button type="submit">Show Diff</button>
-        </td>
-      </tr>);
-
-    $load_ids = array_filter(array($old, $diff->getID()));
-
-    $viewer_id = $this->getRequest()->getViewerContext()->getUserID();
-
-    $raw_objects = queryfx_all(
-      smc_get_db('cdb.differential', 'r'),
-      'SELECT * FROM changeset WHERE changeset.diffID IN (%Ld)',
-      $load_ids);
-
-    $raw_objects = array_group($raw_objects, 'diffID');
-    $objects = $raw_objects[$diff->getID()];
-
-    if (!$objects) {
-      $changesets = array();
-    } else {
-      $changesets = id(new DifferentialChangeset())->loadAllFromArray($objects);
-    }
-
-
-
-    $feedback = id(new DifferentialFeedback())->loadAllWithRevision($revision);
-    $feedback = array_merge($implied_feedback, $feedback);
-
-    $inline_comments = $this->loadInlineComments($feedback, $changesets);
-
-    $diff_map = array();
-    $diffs = array_psort($diffs, 'getID');
-    foreach ($diffs as $diff) {
-      $diff_map[$diff->getID()] = count($diff_map) + 1;
-    }
-    $visible_changesets = array_fill_keys($visible_changesets, true);
-    $hidden_changesets = array();
-    foreach ($changesets as $changeset) {
-      $id = $changeset->getID();
-      if (isset($visible_changesets[$id])) {
-        continue;
-      }
-      $hidden_changesets[$id] = $diff_map[$changeset->getDiffID()];
-    }
-
-
-    $engine = new RemarkupEngine();
-    $engine->enableFeature(RemarkupEngine::FEATURE_GUESS_IMAGES);
-    $engine->enableFeature(RemarkupEngine::FEATURE_YOUTUBE);
-    $engine->setCurrentSandcastle($this->getSandcastleURI($target_diff));
-
-    $syntax_link =
-      <a href={'http://www.intern.facebook.com/intern/wiki/index.php' .
-               '/Articles/Remarkup_Syntax_Reference'}
-         target="_blank"
-         tabindex="4">Remarkup Reference</a>;
-
-
-    $notice = null;
-    if ($this->getRequest()->getBool('diff_changed')) {
-      $notice =
-        <tools:notice title="Revision Updated Recently">
-          This revision was updated with a <strong>new diff</strong> while you
-          were providing feedback. Your inline comments appear on the
-          <strong>old diff</strong>.
-        </tools:notice>;
-    }
-
-    $engineering_repository_id = RepositoryRef::getByCallsign('E')->getID();
-    $svn_revision = $revision->getSVNRevision();
-    if ($status == DifferentialConstants::COMMITTED &&
-        $svn_revision &&
-        $revision->getRepositoryID() == $engineering_repository_id) {
-      $href = '/intern/push/request.php?rev='.$svn_revision;
-      $href = RedirectURI($href)->setTier('intern');
-      $links[] = array(
-        'merge',
-        <a href={$href} id="ask_for_merge_link">Ask for Merge</a>,
-      );
-    }
-
-  }
-
-
-  protected function renderDiffPropertyMoreLink(Diff $diff, $name) {
-    $target = <div class="star-more"
-                   style="display: none;">
-                <div class="star-loading">Loading...</div>
-              </div>;
-    $meta = array(
-      'target'  => $target->requireUniqueID(),
-      'uri'     => '/differential/diffprop/'.$diff->getID().'/'.$name.'/',
-    );
-    $more =
-      <span sigil="star-link-container">
-        &middot;
-        <a mustcapture="true"
-                 sigil="star-more"
-                  href="#"
-                  meta={$meta}>Show Details</a>
-      </span>;
-    return <x:frag>{$more}{$target}</x:frag>;
-  }
-
-
-
-  protected function getRevisionStatusDisplay(DifferentialRevision $revision) {
-    $viewer_id = $this->getRequest()->getViewerContext()->getUserID();
-    $viewer_is_owner = ($viewer_id == $revision->getOwnerID());
-    $status = $revision->getStatus();
-
-    $more = null;
-    switch ($status) {
-      case DifferentialConstants::NEEDS_REVIEW:
-        $message = 'Pending Review';
-        break;
-      case DifferentialConstants::NEEDS_REVISION:
-        $message = 'Awaiting Revision';
-        if ($viewer_is_owner) {
-          $more = 'Make the requested changes and update the revision.';
-        }
-        break;
-      case DifferentialConstants::ACCEPTED:
-        $message = 'Ready for Commit';
-        if ($viewer_is_owner) {
-          $more =
-            <x:frag>
-              Run <tt>arc commit</tt> (svn) or <tt>arc amend</tt> (git) to
-              proceed.
-            </x:frag>;
-        }
-        break;
-      case DifferentialConstants::COMMITTED:
-        $message = 'Committed';
-        $ref = $revision->getRevisionRef();
-        $more = $ref
-                ? (<a href={URI($ref->getDetailURL())}>
-                     {$ref->getName()}
-                   </a>)
-                : null;
-
-        $engineering_repository_id = RepositoryRef::getByCallsign('E')->getID();
-        if ($revision->getSVNRevision() &&
-            $revision->getRepositoryID() == $engineering_repository_id) {
-          Javelin::initBehavior(
-            'differential-revtracker-status',
-            array(
-              'uri' => '/differential/revtracker/'.$revision->getID().'/',
-              'statusId' => 'revtracker_status',
-              'mergeLinkId' => 'ask_for_merge_link',
-            ));
-        }
-        break;
-      case DifferentialConstants::ABANDONED:
-        $message = 'Abandoned';
-        break;
-      default:
-        throw new Exception("Unknown revision status.");
-    }
-
-    if ($more) {
-      $message =
-        <x:frag>
-          <strong id="revtracker_status">{$message}</strong>
-          &middot; {$more}
-        </x:frag>;
-    } else {
-      $message = <strong id="revtracker_status">{$message}</strong>;
-    }
-
-    return $message;
-  }
-
-}
-  protected function getDetailFields(
-    DifferentialRevision $revision,
-    Diff $diff,
-    array $handles) {
-
-    $sandcastle = $this->getSandcastleURI($diff);
-    if ($sandcastle) {
-      $fields['Sandcastle'] = <a href={$sandcastle}>{$sandcastle}</a>;
-    }
-
-
-    $blame_rev = $revision->getSvnBlameRevision();
-    if ($blame_rev) {
-      if ($revision->getRepositoryRef() && is_numeric($blame_rev)) {
-        $ref = new RevisionRef($revision->getRepositoryRef(), $blame_rev);
-        $fields['Blame Revision'] =
-          <a href={URI($ref->getDetailURL())}>
-            {$ref->getName()}
-          </a>;
-      } else {
-        $fields['Blame Revision'] = $blame_rev;
-      }
-    }
-
-
-    $bugzilla_id = $revision->getBugzillaID();
-    if ($bugzilla_id) {
-      $href = 'http://bugs.developers.facebook.com/show_bug.cgi?id='.
-        $bugzilla_id;
-      $fields['Bugzilla'] = <a href={$href}>{'#'.$bugzilla_id}</a>;
-    }
-
-    $fields['Apply Patch'] = <tt>arc patch --revision {$revision->getID()}</tt>;
-
-    if ($diff->getParentRevisionID()) {
-      $parent = id(new DifferentialRevision())->load(
-        $diff->getParentRevisionID());
-      if ($parent) {
-        $fields['Depends On'] =
-          <a href={$parent->getURI()}>
-            D{$parent->getID()}: {$parent->getName()}
-          </a>;
-      }
-    }
-
-    Javelin::initBehavior('differential-star-more');
-    if ($unit_details) {
-      $fields['Unit Tests'] =
-        <x:frag>
-          {$fields['Unit Tests']}
-          {$this->renderDiffPropertyMoreLink($diff, 'unit')}
-        </x:frag>;
-    }
-
-    $platform_impact = $revision->getPlatformImpact();
-    if ($platform_impact) {
-      $fields['Platform Impact'] =
-        <text linebreaks="true">{$platform_impact}</text>;
-    }
-
-    return $fields;
-  }
-
-
-*/
diff --git a/src/applications/differential/controller/revisionview/__init__.php b/src/applications/differential/controller/revisionview/__init__.php
index 3308871f2..90c9a5be5 100644
--- a/src/applications/differential/controller/revisionview/__init__.php
+++ b/src/applications/differential/controller/revisionview/__init__.php
@@ -1,37 +1,38 @@
 <?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/differential/constants/action');
 phutil_require_module('phabricator', 'applications/differential/constants/revisionstatus');
 phutil_require_module('phabricator', 'applications/differential/controller/base');
+phutil_require_module('phabricator', 'applications/differential/parser/changeset');
 phutil_require_module('phabricator', 'applications/differential/storage/changeset');
 phutil_require_module('phabricator', 'applications/differential/storage/comment');
 phutil_require_module('phabricator', 'applications/differential/storage/diffproperty');
 phutil_require_module('phabricator', 'applications/differential/storage/inlinecomment');
 phutil_require_module('phabricator', 'applications/differential/storage/revision');
 phutil_require_module('phabricator', 'applications/differential/storage/viewtime');
 phutil_require_module('phabricator', 'applications/differential/view/addcomment');
 phutil_require_module('phabricator', 'applications/differential/view/changesetlistview');
 phutil_require_module('phabricator', 'applications/differential/view/difftableofcontents');
 phutil_require_module('phabricator', 'applications/differential/view/revisioncommentlist');
 phutil_require_module('phabricator', 'applications/differential/view/revisiondetail');
 phutil_require_module('phabricator', 'applications/differential/view/revisionupdatehistory');
 phutil_require_module('phabricator', 'applications/draft/storage/draft');
 phutil_require_module('phabricator', 'applications/phid/constants');
 phutil_require_module('phabricator', 'applications/phid/handle/data');
 phutil_require_module('phabricator', 'infrastructure/celerity/api');
 phutil_require_module('phabricator', 'infrastructure/env');
 phutil_require_module('phabricator', 'view/form/error');
 
 phutil_require_module('phutil', 'markup');
 phutil_require_module('phutil', 'symbols');
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('DifferentialRevisionViewController.php');
diff --git a/src/applications/differential/tasks/DifferentialTasksAttacher.php b/src/applications/differential/tasks/DifferentialTasksAttacher.php
index 72576ae25..ef3a34b40 100644
--- a/src/applications/differential/tasks/DifferentialTasksAttacher.php
+++ b/src/applications/differential/tasks/DifferentialTasksAttacher.php
@@ -1,29 +1,40 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 abstract class DifferentialTasksAttacher {
   /**
    * Implementation of this function should attach given tasks to
    * the given revision. The function is called when 'arc' has task
    * ids defined in the commit message.
    */
   abstract public function attachTasksToRevision(
     $user_phid,
     DifferentialRevision $revision,
     array $task_ids);
+
+  /**
+   * This method will be called with a task and its original and new
+   * associated revisions. Implementation of this method should update
+   * the affected revisions to maintain the new associations.
+   */
+  abstract public function updateTaskRevisionAssoc(
+    $task_phid,
+    array $orig_rev_phids,
+    array $new_rev_phids);
+
 }
diff --git a/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php b/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php
index 35eacc4c9..2d77947dc 100644
--- a/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php
+++ b/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php
@@ -1,141 +1,141 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 class DifferentialChangesetListView extends AphrontView {
 
   private $changesets = array();
   private $editable;
   private $revision;
   private $renderURI = '/differential/changeset/';
   private $vsMap = array();
-  private $whitespace = null;
+  private $whitespace;
 
   public function setChangesets($changesets) {
     $this->changesets = $changesets;
     return $this;
   }
 
   public function setEditable($editable) {
     $this->editable = $editable;
     return $this;
   }
 
   public function setRevision(DifferentialRevision $revision) {
     $this->revision = $revision;
     return $this;
   }
 
   public function setVsMap(array $vs_map) {
     $this->vsMap = $vs_map;
     return $this;
   }
 
   public function setRenderURI($render_uri) {
     $this->renderURI = $render_uri;
     return $this;
   }
 
   public function setWhitespace($whitespace) {
     $this->whitespace = $whitespace;
     return $this;
   }
 
   public function render() {
     require_celerity_resource('differential-changeset-view-css');
 
     $vs_map = $this->vsMap;
     $changesets = $this->changesets;
 
     $output = array();
     $mapping = array();
     foreach ($changesets as $key => $changeset) {
       $file = $changeset->getFilename();
       $class = 'differential-changeset';
       if (!$this->editable) {
         $class .= ' differential-changeset-noneditable';
       }
       $id = $changeset->getID();
       if ($id) {
         $vs_id = idx($vs_map, $id);
       } else {
         $vs_id = null;
       }
 
       $ref = $changeset->getRenderingReference();
 
       $detail_uri = new PhutilURI($this->renderURI);
       $detail_uri->setQueryParams(
         array(
           'id'          => $ref,
           'vs'          => $vs_id,
           'whitespace'  => $this->whitespace,
         ));
 
       $detail_button = phutil_render_tag(
         'a',
         array(
           'style'   => 'float: right',
           'class'   => 'button small grey',
           'href'    => $detail_uri,
           'target'  => '_blank',
         ),
         'Standalone View');
 
       $uniq_id = celerity_generate_unique_node_id();
 
       $detail = new DifferentialChangesetDetailView();
       $detail->setChangeset($changeset);
       $detail->addButton($detail_button);
       $detail->appendChild(
         phutil_render_tag(
           'div',
           array(
             'id' => $uniq_id,
           ),
           '<div class="differential-loading">Loading...</div>'));
       $output[] = $detail->render();
 
       $mapping[$uniq_id] = array(
         $ref,
         $vs_id);
     }
 
     Javelin::initBehavior('differential-populate', array(
       'registry'    => $mapping,
       'whitespace'  => $this->whitespace,
       'uri'         => $this->renderURI,
     ));
 
     Javelin::initBehavior('differential-show-more', array(
       'uri' => $this->renderURI,
     ));
 
     if ($this->editable) {
       $revision = $this->revision;
       Javelin::initBehavior('differential-edit-inline-comments', array(
         'uri' => '/differential/comment/inline/edit/'.$revision->getID().'/',
       ));
     }
 
     return
       '<div class="differential-review-stage">'.
         implode("\n", $output).
       '</div>';
   }
 
 }
diff --git a/src/applications/differential/view/difftableofcontents/DifferentialDiffTableOfContentsView.php b/src/applications/differential/view/difftableofcontents/DifferentialDiffTableOfContentsView.php
index d67e6bbec..4c6508d7c 100644
--- a/src/applications/differential/view/difftableofcontents/DifferentialDiffTableOfContentsView.php
+++ b/src/applications/differential/view/difftableofcontents/DifferentialDiffTableOfContentsView.php
@@ -1,172 +1,177 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 final class DifferentialDiffTableOfContentsView extends AphrontView {
 
   private $changesets = array();
   private $standaloneViewLink = null;
   private $renderURI = '/differential/changeset/';
   private $revisionID;
+  private $whitespace;
 
   public function setChangesets($changesets) {
     $this->changesets = $changesets;
     return $this;
   }
 
   public function setStandaloneViewLink($standalone_view_link) {
     $this->standaloneViewLink = $standalone_view_link;
     return $this;
   }
 
   public function setVsMap(array $vs_map) {
     $this->vsMap = $vs_map;
     return $this;
   }
 
   public function setRevisionID($revision_id) {
     $this->revisionID = $revision_id;
     return $this;
   }
 
+  public function setWhitespace($whitespace) {
+    $this->whitespace = $whitespace;
+    return $this;
+  }
 
   public function render() {
 
     require_celerity_resource('differential-core-view-css');
     require_celerity_resource('differential-table-of-contents-css');
 
     $rows = array();
 
     $changesets = $this->changesets;
     foreach ($changesets as $changeset) {
       $file = $changeset->getFilename();
       $display_file = $changeset->getDisplayFilename();
 
       $type = $changeset->getChangeType();
       $ftype = $changeset->getFileType();
 
       if (DifferentialChangeType::isOldLocationChangeType($type)) {
         $link = phutil_escape_html($display_file);
         $away = $changeset->getAwayPaths();
         if (count($away) > 1) {
           $meta = array();
           if ($type == DifferentialChangeType::TYPE_MULTICOPY) {
             $meta[] = 'Deleted after being copied to multiple locations:';
           } else {
             $meta[] = 'Copied to multiple locations:';
           }
           foreach ($away as $path) {
             $meta[] = $path;
           }
           $meta = implode('<br />', $meta);
         } else {
           if ($type == DifferentialChangeType::TYPE_MOVE_AWAY) {
             $meta = 'Moved to '.reset($away);
           } else {
             $meta = 'Copied to '.reset($away);
           }
         }
       } else {
 
         if ($this->standaloneViewLink) {
           $id = $changeset->getID();
           if ($id) {
             $vs_id = idx($this->vsMap, $id);
           } else {
             $vs_id = null;
           }
           $ref = $changeset->getRenderingReference();
           $detail_uri = new PhutilURI($this->renderURI);
           $detail_uri->setQueryParams(
             array(
               'id'          => $ref,
               'vs'          => $vs_id,
-              'whitespace'  => 'TODO',
+              'whitespace'  => $this->whitespace,
               'revision_id' => $this->revisionID,
             ));
 
           $link = phutil_render_tag(
             'a',
             array(
               'href' => $detail_uri,
               'target'  => '_blank',
             ),
             phutil_escape_html($display_file));
         } else {
           $link = phutil_render_tag(
             'a',
             array(
               'href' => '#'.$changeset->getAnchorName(),
             ),
             phutil_escape_html($display_file));
         }
 
         if ($type == DifferentialChangeType::TYPE_MOVE_HERE) {
           $meta = 'Moved from '.phutil_escape_html($changeset->getOldFile());
         } else if ($type == DifferentialChangeType::TYPE_COPY_HERE) {
           $meta = 'Copied from '.phutil_escape_html($changeset->getOldFile());
         } else {
           $meta = null;
         }
       }
 
       $line_count = $changeset->getAffectedLineCount();
       if ($line_count == 0) {
         $lines = null;
       } else if ($line_count == 1) {
         $lines = ' (1 line)';
       } else {
         $lines = ' ('.$line_count.' lines)';
       }
 
       $char = DifferentialChangeType::getSummaryCharacterForChangeType($type);
       $chartitle = DifferentialChangeType::getFullNameForChangeType($type);
       $desc = DifferentialChangeType::getShortNameForFileType($ftype);
       if ($desc) {
         $desc = '('.$desc.')';
       }
       $pchar =
         ($changeset->getOldProperties() === $changeset->getNewProperties())
           ? null
           : '<span title="Properties Changed">M</span>';
 
       $rows[] =
         '<tr>'.
           '<td class="differential-toc-char" title='.$chartitle.'>'.$char.
           '</td>'.
           '<td class="differential-toc-prop">'.$pchar.'</td>'.
           '<td class="differential-toc-ftype">'.$desc.'</td>'.
           '<td class="differential-toc-file">'.$link.$lines.'</td>'.
         '</tr>';
       if ($meta) {
         $rows[] =
           '<tr>'.
             '<td colspan="3"></td>'.
             '<td class="differential-toc-meta">'.$meta.'</td>'.
           '</tr>';
       }
     }
 
     return
       '<div class="differential-toc differential-panel">'.
         '<h1>Table of Contents</h1>'.
         '<table>'.
           implode("\n", $rows).
         '</table>'.
       '</div>';
   }
 }